it-swarm-ja.com

Java AES / CBC復号化後の初期バイトが正しくない

次の例の何が問題になっていますか?

問題は、復号化された文字列の最初の部分が意味をなさないことです。しかし、残りは大丈夫です、私は...

Result: `£eB6O�geS��i are you? Have a Nice day.
@Test
public void testEncrypt() {
  try {
    String s = "Hello there. How are you? Have a Nice day.";

    // Generate key
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(128);
    SecretKey aesKey = kgen.generateKey();

    // Encrypt cipher
    Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey);

    // Encrypt
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, encryptCipher);
    cipherOutputStream.write(s.getBytes());
    cipherOutputStream.flush();
    cipherOutputStream.close();
    byte[] encryptedBytes = outputStream.toByteArray();

    // Decrypt cipher
    Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
    decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);

    // Decrypt
    outputStream = new ByteArrayOutputStream();
    ByteArrayInputStream inStream = new ByteArrayInputStream(encryptedBytes);
    CipherInputStream cipherInputStream = new CipherInputStream(inStream, decryptCipher);
    byte[] buf = new byte[1024];
    int bytesRead;
    while ((bytesRead = cipherInputStream.read(buf)) >= 0) {
        outputStream.write(buf, 0, bytesRead);
    }

    System.out.println("Result: " + new String(outputStream.toByteArray()));

  } 
  catch (Exception ex) {
    ex.printStackTrace();
  }
}
107
TedTrippin

私自身を含む多くの人が、Base64への変換を忘れる、初期化ベクトル、文字セットなどの情報が欠落しているために、この作業を行う際に多くの問題に直面しています。

これが皆さんのお役に立つことを願っています。コンパイルするには、追加のApache Commons Codec jarが必要です。 http://commons.Apache.org/proper/commons-codec/download_codec .cgi

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.Apache.commons.codec.binary.Base64;

public class Encryptor {
    public static String encrypt(String key, String initVector, String value) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

            byte[] encrypted = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string: "
                    + Base64.encodeBase64String(encrypted));

            return Base64.encodeBase64String(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static String decrypt(String key, String initVector, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

            byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {
        String key = "Bar12345Bar12345"; // 128 bit key
        String initVector = "RandomInitVector"; // 16 bytes IV

        System.out.println(decrypt(key, initVector,
                encrypt(key, initVector, "Hello World")));
    }
}
238

ここで Apache Commons CodecBase64を使わない解法:

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AdvancedEncryptionStandard
{
    private byte[] key;

    private static final String ALGORITHM = "AES";

    public AdvancedEncryptionStandard(byte[] key)
    {
        this.key = key;
    }

    /**
     * Encrypts the given plain text
     *
     * @param plainText The plain text to encrypt
     */
    public byte[] encrypt(byte[] plainText) throws Exception
    {
        SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        return cipher.doFinal(plainText);
    }

    /**
     * Decrypts the given byte array
     *
     * @param cipherText The data to decrypt
     */
    public byte[] decrypt(byte[] cipherText) throws Exception
    {
        SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        return cipher.doFinal(cipherText);
    }
}

使用例

byte[] encryptionKey = "MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8);
byte[] plainText = "Hello world!".getBytes(StandardCharsets.UTF_8);
AdvancedEncryptionStandard advancedEncryptionStandard = new AdvancedEncryptionStandard(
        encryptionKey);
byte[] cipherText = advancedEncryptionStandard.encrypt(plainText);
byte[] decryptedCipherText = advancedEncryptionStandard.decrypt(cipherText);

System.out.println(new String(plainText));
System.out.println(new String(cipherText));
System.out.println(new String(decryptedCipherText));

プリント:

Hello world!
դ;��LA+�ߙb*
Hello world!
41
BullyWiiPlaza

初期化ベクトル(IV)を正しく扱っていないようです。 AES、IV、ブロックチェーンについて最後に読んでから長い時間が経ちましたが、あなたの話

IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());

oKではないようです。 AESの場合、初期化ベクトルは暗号インスタンスの「初期状態」と考えることができます。この状態は、鍵からではなく暗号化暗号の実際の計算から取得できる情報のビットです。 (IVがキーから抽出されることができるならば、そのキーは初期化フェーズの間に暗号インスタンスに既に与えられているので、それは役に立たないだろうと主張するかもしれません)。

したがって、暗号化の最後に、暗号インスタンスからIVをbyte []として取得する必要があります。

  cipherOutputStream.close();
  byte[] iv = encryptCipher.getIV();

そしてこのbyte []でDECRYPT_MODEの中のCipherを初期化するべきです:

  IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

その後、あなたの復号化は問題ないはずです。お役に立てれば。

23
GPI

復号化に使用しているIVが正しくありません。このコードを置き換える

//Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);

このコードでは

//Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptCipher.getIV());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);

そしてそれはあなたの問題を解決するはずです。


以下は、Javaの単純なAESクラスの例です。アプリケーションの特定のニーズすべてを説明できない可能性があるため、本番環境でこのクラスを使用することはお勧めしません。

import Java.nio.charset.StandardCharsets;
import Java.security.InvalidAlgorithmParameterException;
import Java.security.InvalidKeyException;
import Java.security.NoSuchAlgorithmException;
import Java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import Java.util.Base64;

public class AES 
{
    public static byte[] encrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
    {       
        return AES.transform(Cipher.ENCRYPT_MODE, keyBytes, ivBytes, messageBytes);
    }

    public static byte[] decrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
    {       
        return AES.transform(Cipher.DECRYPT_MODE, keyBytes, ivBytes, messageBytes);
    }

    private static byte[] transform(final int mode, final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
    {
        final SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        final IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        byte[] transformedBytes = null;

        try
        {
            final Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

            cipher.init(mode, keySpec, ivSpec);

            transformedBytes = cipher.doFinal(messageBytes);
        }        
        catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) 
        {
            e.printStackTrace();
        }
        return transformedBytes;
    }

    public static void main(final String[] args) throws InvalidKeyException, InvalidAlgorithmParameterException
    {
        //Retrieved from a protected local file.
        //Do not hard-code and do not version control.
        final String base64Key = "ABEiM0RVZneImaq7zN3u/w==";

        //Retrieved from a protected database.
        //Do not hard-code and do not version control.
        final String shadowEntry = "AAECAwQFBgcICQoLDA0ODw==:ZtrkahwcMzTu7e/WuJ3AZmF09DE=";

        //Extract the iv and the ciphertext from the shadow entry.
        final String[] shadowData = shadowEntry.split(":");        
        final String base64Iv = shadowData[0];
        final String base64Ciphertext = shadowData[1];

        //Convert to raw bytes.
        final byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        final byte[] ivBytes = Base64.getDecoder().decode(base64Iv);
        final byte[] encryptedBytes = Base64.getDecoder().decode(base64Ciphertext);

        //Decrypt data and do something with it.
        final byte[] decryptedBytes = AES.decrypt(keyBytes, ivBytes, encryptedBytes);

        //Use non-blocking SecureRandom implementation for the new IV.
        final SecureRandom secureRandom = new SecureRandom();

        //Generate a new IV.
        secureRandom.nextBytes(ivBytes);

        //At this point instead of printing to the screen, 
        //one should replace the old shadow entry with the new one.
        System.out.println("Old Shadow Entry      = " + shadowEntry);
        System.out.println("Decrytped Shadow Data = " + new String(decryptedBytes, StandardCharsets.UTF_8));
        System.out.println("New Shadow Entry      = " + Base64.getEncoder().encodeToString(ivBytes) + ":" + Base64.getEncoder().encodeToString(AES.encrypt(keyBytes, ivBytes, decryptedBytes)));
    }
}

AESはエンコーディングとは何の関係もないことに注意してください。そのため、サードパーティのライブラリを使用せずに、別々に処理することを選択しました。

17
k170

この回答では、特定のデバッグの質問ではなく、「シンプルJava AES暗号化/復号化の例」メインテーマにアプローチすることを選択します。

これは私の JavaでのAES暗号化に関するブログ投稿 の簡単な要約です。したがって、何かを実装する前にこれを読むことをお勧めします。ただし、使用する簡単な例を提供し、注意すべき点をいくつか示します。

この例では、 認証された暗号化Galois/Counter ModeまたはGCM モードで使用することを選択します。その理由は、ほとんどの場合、 完全性と信頼性と組み合わせた信頼性 (詳細は blog を参照)が必要だからです。

AES-GCM暗号化/復号化チュートリアル

AES-GCMJava Cryptography Architecture(JCA) で暗号化/復号化するために必要な手順は次のとおりです。 他の例と混同しないでください。微妙な違いによりコードが完全に安全でなくなる可能性があります。

1.キーを作成する

ユースケースに依存するため、最も単純なケースであるランダムな秘密鍵を想定します。

SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");

重要:

2.初期化ベクトルを作成する

初期化ベクトル(IV) を使用して、同じ秘密鍵が異なる 暗号文 を作成するようにします。

byte[] IV = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(IV);

重要:

3. IVとキーで暗号化する

final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, IV); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);

重要:

  • 16バイト/ 128ビットを使用 認証タグ (整合性/認証性の検証に使用)
  • 認証タグは自動的に暗号化テキストに追加されます(JCA実装で)
  • gCMはストリーム暗号のように動作するため、パディングは不要です
  • CipherInputStream を使用して、大量のデータを暗号化する場合
  • 変更された場合に追加の(非機密)データをチェックしたいですか? 関連データ with cipher.updateAAD(associatedData);詳細はこちら を使用できます。

3.単一メッセージへのシリアル化

IVと暗号文を追加するだけです。前述のように、IVは秘密である必要はありません。

ByteBuffer byteBuffer = ByteBuffer.allocate(4 + IV.length + cipherText.length);
byteBuffer.putInt(IV.length);
byteBuffer.put(IV);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();

文字列表現が必要な場合は、オプションで Base64 でエンコードします。 Android's または Java 8のビルトイン 実装を使用します(Apache Commons Codecは使用しないでください-ひどい実装です)。エンコードは、バイト配列を文字列表現に「変換」して、ASCIIを安全にするために使用されます。例:

String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);

4.復号化の準備:デシリアライズ

メッセージをエンコードした場合は、まずバイト配列にデコードします:

byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)

その後、メッセージを分解します

ByteBuffer byteBuffer = ByteBuffer.wrap(cipherMessage);
int ivLength = byteBuffer.getInt();
if(ivLength < 12 || ivLength >= 16) { // check input parameter
    throw new IllegalArgumentException("invalid IV length");
}
byte[] IV = new byte[ivLength];
byteBuffer.get(IV);
byte[] cipherText = new byte[byteBuffer.remaining()];
byteBuffer.get(cipherText);

重要:

  • 入力パラメータ を検証するように注意してください。したがって、 サービス拒否攻撃 を回避するには、メモリを割り当てすぎます(たとえば、攻撃者が長さの値を2³¹に割り当てて2GBのヒープを割り当てます)

5.復号化

暗号を初期化し、暗号化と同じパラメーターを設定します。

final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, IV));
byte[] plainText= cipher.doFinal(cipherText);

重要:

  • 暗号化中に追加した場合、 関連付けられたデータcipher.updateAAD(associatedData);とともに追加することを忘れないでください。

最新のAndroid(SDK 21+)およびJava(7+)実装にはAES-GCMが必要であることに注意してください。古いバージョンには欠けている場合があります。 Encrypt-then-Mac (たとえば AES-CBC +-の同様のモードと比較してより効率的であることに加えて、実装が簡単なので、このモードを選択します。 HMAC )。 HMACでAES-CBCを実装する方法に関するこの記事を参照

15
patrickf

オンラインエディタRunnableのバージョン: -

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
//import org.Apache.commons.codec.binary.Base64;
import Java.util.Base64;

public class Encryptor {
    public static String encrypt(String key, String initVector, String value) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));

            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

            byte[] encrypted = cipher.doFinal(value.getBytes());

            //System.out.println("encrypted string: "
              //      + Base64.encodeBase64String(encrypted));

            //return Base64.encodeBase64String(encrypted);
            String s = new String(Base64.getEncoder().encode(encrypted));
            return s;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String key, String initVector, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

            byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted));

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {
        String key = "Bar12345Bar12345"; // 128 bit key
        String initVector = "RandomInitVector"; // 16 bytes IV

        System.out.println(encrypt(key, initVector, "Hello World"));
        System.out.println(decrypt(key, initVector, encrypt(key, initVector, "Hello World")));
    }
}
2
Bhupesh Pant

これは一般に認められている答えに対する改善です。

変更点

(1)ランダムIVを使って暗号化テキストの前に付ける

(2)パスフレーズから鍵を生成するためのSHA-256の使用

(3)Apache Commonsに依存しない

public static void main(String[] args) throws GeneralSecurityException {
    String plaintext = "Hello world";
    String passphrase = "My passphrase";
    String encrypted = encrypt(passphrase, plaintext);
    String decrypted = decrypt(passphrase, encrypted);
    System.out.println(encrypted);
    System.out.println(decrypted);
}

private static SecretKeySpec getKeySpec(String passphrase) throws NoSuchAlgorithmException {
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    return new SecretKeySpec(digest.digest(passphrase.getBytes(UTF_8)), "AES");
}

private static Cipher getCipher() throws NoSuchPaddingException, NoSuchAlgorithmException {
    return Cipher.getInstance("AES/CBC/PKCS5PADDING");
}

public static String encrypt(String passphrase, String value) throws GeneralSecurityException {
    byte[] initVector = new byte[16];
    SecureRandom.getInstanceStrong().nextBytes(initVector);
    Cipher cipher = getCipher();
    cipher.init(Cipher.ENCRYPT_MODE, getKeySpec(passphrase), new IvParameterSpec(initVector));
    byte[] encrypted = cipher.doFinal(value.getBytes());
    return DatatypeConverter.printBase64Binary(initVector) +
            DatatypeConverter.printBase64Binary(encrypted);
}

public static String decrypt(String passphrase, String encrypted) throws GeneralSecurityException {
    byte[] initVector = DatatypeConverter.parseBase64Binary(encrypted.substring(0, 24));
    Cipher cipher = getCipher();
    cipher.init(Cipher.DECRYPT_MODE, getKeySpec(passphrase), new IvParameterSpec(initVector));
    byte[] original = cipher.doFinal(DatatypeConverter.parseBase64Binary(encrypted.substring(24)));
    return new String(original);
}
1
wvdz

Spring BootでJava.util.Base64を使用する別のソリューション

暗号化クラス

package com.jmendoza.springboot.crypto.cipher;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import Java.nio.charset.StandardCharsets;
import Java.util.Base64;

@Component
public class Encryptor {

    @Value("${security.encryptor.key}")
    private byte[] key;
    @Value("${security.encryptor.algorithm}")
    private String algorithm;

    public String encrypt(String plainText) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(key, algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return new String(Base64.getEncoder().encode(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8))));
    }

    public String decrypt(String cipherText) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(key, algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
    }
}

EncryptorControllerクラス

package com.jmendoza.springboot.crypto.controller;

import com.jmendoza.springboot.crypto.cipher.Encryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/cipher")
public class EncryptorController {

    @Autowired
    Encryptor encryptor;

    @GetMapping(value = "encrypt/{value}")
    public String encrypt(@PathVariable("value") final String value) throws Exception {
        return encryptor.encrypt(value);
    }

    @GetMapping(value = "decrypt/{value}")
    public String decrypt(@PathVariable("value") final String value) throws Exception {
        return encryptor.decrypt(value);
    }
}

application.properties

server.port=8082
security.encryptor.algorithm=AES
security.encryptor.key=M8jFt46dfJMaiJA0

http:// localhost:8082/cipher/encrypt/jmendoza

2h41HH8Shzc4BRU3hVDOXA ==

http:// localhost:8082/cipher/decrypt/2h41HH8Shzc4BRU3hVDOXA ==

メンドーサ

Github: https://github.com/JonathanM2ndoza/Spring-Boot-Crypto

1

標準ライブラリが提供する解決策に頼るのは良い考えです:

private static void stackOverflow15554296()
    throws
        NoSuchAlgorithmException, NoSuchPaddingException,        
        InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException
{

    // prepare key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    SecretKey aesKey = keygen.generateKey();
    String aesKeyForFutureUse = Base64.getEncoder().encodeToString(
            aesKey.getEncoded()
    );

    // cipher engine
    Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

    // cipher input
    aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
    byte[] clearTextBuff = "Text to encode".getBytes();
    byte[] cipherTextBuff = aesCipher.doFinal(clearTextBuff);

    // recreate key
    byte[] aesKeyBuff = Base64.getDecoder().decode(aesKeyForFutureUse);
    SecretKey aesDecryptKey = new SecretKeySpec(aesKeyBuff, "AES");

    // decipher input
    aesCipher.init(Cipher.DECRYPT_MODE, aesDecryptKey);
    byte[] decipheredBuff = aesCipher.doFinal(cipherTextBuff);
    System.out.println(new String(decipheredBuff));
}

これは「エンコードするテキスト」を印刷します。

解決策は、 Java暗号化アーキテクチャリファレンスガイド および https://stackoverflow.com/a/20591539/146745に基づいています。 答え。

1
andrej

最終的にJavaでの暗号化はJava Simplified Encryption(Jasypt)で使用するのが非常に簡単です。別の方法でcypherを使用できます。上記は暗号化および復号化のコード例です。

import Java.security.spec.KeySpec;
import Java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class CypherUtils {

    private static final String AES_CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
    private static final String PBKDF2_WITH_HMAC_SHA256 = "PBKDF2WithHmacSHA256";

    public static String decrypt(String strToDecrypt, String keyCode, String salt) {
        try {
            byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF2_WITH_HMAC_SHA256);
            KeySpec spec = new PBEKeySpec(keyCode.toCharArray(), salt.getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec);
            return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
        } catch (Exception e) {
            System.out.println("Error while decrypting: " + e.toString());
        }
        return null;
    }

    public static String encrypt(String strToEncrypt, String keyCode, String salt) {
        try {
            byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF2_WITH_HMAC_SHA256);
            KeySpec spec = new PBEKeySpec(keyCode.toCharArray(), salt.getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
            return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
        } catch (Exception e) {
            System.out.println("Error while encrypting: " + e.toString());
        }
        return null;
    }
}
0
Tiago Medici