使用公共私钥组合进行Java 8

时间:2016-03-31 07:43:48

标签: java encryption aes

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

我已经在下面添加了我的示例代码,有一条注释表示我引发了异常行。

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

我读到了KDF哈希,但Java似乎没有一种明显的方法可以在我的128byte密钥上调用它。此外,我不确定这是正确的答案,因为我的理解是密钥越长,加密就越安全(对于给定的算法)。也许我需要从使用AES / CBC / PKCS5Padding切换,但JDK标配的其他算法似乎都不支持128byte密钥。

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)

2 个答案:

答案 0 :(得分:0)

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

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

使用有效的AES密钥大小。

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

对于密钥派生,请使用PBKDF2,请参阅Class SecretKeyFactoryJava Cryptography Architecture Standard Algorithm Name Documentation" PBKDF2WithHmacSHA1" (使用基于密码的密钥派生函数功能构造密钥) 有关示例,请参阅OWASP Hashing Java,但请使用" PBKDF2WithHmacSHA1"作为算法。

答案 1 :(得分:0)

代码无法正常工作的原因是我使用的是不兼容的算法。更正如下: 替换行:

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));