使用公共-私有密钥组合与Java 8进行对称加密



我试图使用非对称私钥和公钥组合来生成对称密钥,用于加密和解密某些文本,但是,我无法使用生成的密钥,因为它的大小为128字节,这对于AES加密来说是不可接受的。我想只使用JRE(没有外部库)来解决这个问题。你有解决方案吗?

我在下面包含了我的示例代码,其中有一条注释指示我抛出异常的行。

encryptCipher.init(Cipher.ENCRYPT_MODE, tomSecretKeySpec, iv);

我读过关于KDF散列的文章,但Java似乎没有明显的方法在我的128字节密钥上调用它。此外,我不确定这是正确的答案,因为我的理解是,密钥越长,加密就越安全(对于给定的算法)。也许我需要放弃使用AES/CCBC/PKCS5Padding,但JDK标准中包含的其他算法似乎都不支持128字节密钥。

public void demoSymmetricEncryption() throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
    String keyAlgorithm = "DiffieHellman";
    String keyAgreementAlgorithm = "DiffieHellman";
    String keySpecAlgorithm = "AES";
    String cipherAlgorithm = "AES/CBC/PKCS5Padding";
    KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
    keyGenerator.initialize(1024, new SecureRandom());
    KeyPair tomKeyPair = keyGenerator.generateKeyPair();
    PrivateKey tomPrivateKey = tomKeyPair.getPrivate();
    PublicKey tomPublicKey = tomKeyPair.getPublic();
    KeyPair steveKeyPair = keyGenerator.generateKeyPair();
    PrivateKey stevePrivateKey = steveKeyPair.getPrivate();
    PublicKey stevePublicKey = steveKeyPair.getPublic();
    int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
    System.out.println("Limited encryption policy files installed : " + (maxKeyLen == 128)); // returns false
    KeyAgreement tomKeyAgreement = KeyAgreement.getInstance(keyAgreementAlgorithm);
    keyGenerator.initialize(1024, new SecureRandom());
    tomKeyAgreement.init(tomPrivateKey);
    tomKeyAgreement.doPhase(stevePublicKey, true);
    byte[] tomSecret = tomKeyAgreement.generateSecret();
    SecretKeySpec tomSecretKeySpec = new SecretKeySpec(tomSecret, keySpecAlgorithm);
    KeyAgreement steveKeyAgreement = KeyAgreement.getInstance(keyAgreementAlgorithm);
    steveKeyAgreement.init(stevePrivateKey);
    steveKeyAgreement.doPhase(tomPublicKey, true);
    byte[] steveSecret = steveKeyAgreement.generateSecret();
    SecretKeySpec steveSecretKeySpec = new SecretKeySpec(steveSecret, keySpecAlgorithm);
    System.out.println("Secret Keys are identical : " + steveSecretKeySpec.equals(tomSecretKeySpec)); // returns true
    String initVector = "RandomInitVector";
    Cipher encryptCipher = Cipher.getInstance(cipherAlgorithm);
    IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
    // fails because AES key is 128 bytes not 128 bits in length - think I need to use KDF hash to shrink it appropriately.
    encryptCipher.init(Cipher.ENCRYPT_MODE, tomSecretKeySpec, iv);

    // Attempt to use the cipher
    byte[] encryptedData = encryptCipher.doFinal("Hello".getBytes());
    Cipher decryptCipher = Cipher.getInstance(cipherAlgorithm);
    iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
    decryptCipher.init(Cipher.DECRYPT_MODE, steveSecretKeySpec, iv);
    byte[] decryptedData = decryptCipher.doFinal(encryptedData);
    System.out.println("Decrypted Data : " + new String(decryptedData));
}

程序的输出如下:

Limited encryption policy files installed : false
Secret Keys are identical : true
Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 128 bytes
    at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87)
    at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:91)
    at com.sun.crypto.provider.CipherCore.init(CipherCore.java:582)
    at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:339)
    at javax.crypto.Cipher.implInit(Cipher.java:806)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1396)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at crypto.SymetricEncryptionTest.demoSymmetricEncryption(SymetricEncryptionTest.java:76)
    at crypto.SymetricEncryptionTest.main(SymetricEncryptionTest.java:29)

错误为:*AES密钥长度无效:128字节*

有效的AES密钥大小为128位、192位和256位或以字节为单位:16字节、24字节和32字节。

请使用有效的AES密钥大小。

生成对称密钥的一般方法只是从加密PRNG中获取字节。对于Java,请参见Class SecureRondom。

有关使用PBKDF2的密钥派生,请参阅Class SecretKeyFactory和Java Cryptography Architecture标准算法名称文档"PBKDF2WithHmacSHA1"(使用基于密码的密钥派生函数函数构建密钥)
有关示例,请参阅OWASP散列Java,但使用"PBKDF2WithHmacSHA1"作为算法。

代码不起作用的原因是我使用了不兼容的算法。更正如下:更换线路:

String keyAlgorithm = "DiffieHellman";
String keyAgreementAlgorithm = "DiffieHellman";

带有

String keyAlgorithm = "EC";
String keyAgreementAlgorithm = "ECDH";
int keySize = 128;

并更换线路

keyGenerator.initialize(1024, new SecureRandom());

带有

keyGenerator.initialize(keySize, new SecureRandom());

程序现在产生输出:

Limited encryption policy files installed : false
Secret Keys are identical : true
Decrypted Data : Hello

从技术上讲,您可能还想对加密输出进行Base64编码,然后在解码之前再次解码,如下所示:

String encryptedData = Base64.encode(encryptCipher.doFinal("Hello".getBytes()));
byte[] decryptedData = decryptCipher.doFinal(Base64.decode(encryptedData));

最新更新