我希望能够根据 ECDH
key 协议(protocol)生成正确的 AES
key 。但是,当我生成 key 时,我得到的 key 长度无效,通常为 66 位。错误如下:
java.security.InvalidKeyException: Key length not 128/192/256 bits.
Encrypted cipher text: null
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineInit(Unknown Source)
at javax.crypto.Cipher.init(Cipher.java:1346)
at javax.crypto.Cipher.init(Cipher.java:1282)
at Test.encryptString(Test.java:99)
at Test.main(Test.java:44)
这是生成此异常的相关代码:
public static byte[] iv = new SecureRandom().generateSeed(16);
public static void main(String[] args) {
String plainText = "Look mah, I'm a message!";
System.out.println("Original plaintext message: " + plainText);
// Initialize two key pairs
KeyPair keyPairA = generateECKeys();
KeyPair keyPairB = generateECKeys();
// Create two AES secret keys to encrypt/decrypt the message
SecretKey secretKeyA = generateSharedSecret(keyPairA.getPrivate(),
keyPairB.getPublic());
System.out.println(bytesToHex(secretKeyA.getEncoded()));
SecretKey secretKeyB = generateSharedSecret(keyPairB.getPrivate(),
keyPairA.getPublic());
System.out.println(bytesToHex(secretKeyB.getEncoded()));
// Encrypt the message using 'secretKeyA'
String cipherText = encryptString(secretKeyA, plainText);
System.out.println("Encrypted cipher text: " + cipherText);
// Decrypt the message using 'secretKeyB'
String decryptedPlainText = decryptString(secretKeyB, cipherText);
System.out.println("Decrypted cipher text: " + decryptedPlainText);
}
public static KeyPair generateECKeys() {
try {
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("secp521r1");
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
"ECDH", "BC");
keyPairGenerator.initialize(parameterSpec);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
System.out.println("Private key length: "
+ keyPair.getPrivate().getEncoded().length);
System.out.println("Public key length: "
+ keyPair.getPublic().getEncoded().length);
return keyPair;
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
| NoSuchProviderException e) {
e.printStackTrace();
return null;
}
}
public static SecretKey generateSharedSecret(PrivateKey privateKey,
PublicKey publicKey) {
try {
KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "BC");
keyAgreement.init(privateKey);
keyAgreement.doPhase(publicKey, true);
SecretKey key = keyAgreement.generateSecret("AES");
System.out.println("Shared key length: " + key.getEncoded().length);
return key;
} catch (InvalidKeyException | NoSuchAlgorithmException
| NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static String encryptString(SecretKey key, String plainText) {
try {
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
byte[] plainTextBytes = plainText.getBytes("UTF-8");
byte[] cipherText;
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
cipherText = new byte[cipher.getOutputSize(plainTextBytes.length)];
int encryptLength = cipher.update(plainTextBytes, 0,
plainTextBytes.length, cipherText, 0);
encryptLength += cipher.doFinal(cipherText, encryptLength);
return bytesToHex(cipherText);
} catch (NoSuchAlgorithmException | NoSuchProviderException
| NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException
| UnsupportedEncodingException | ShortBufferException
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
return null;
}
}
public static String decryptString(SecretKey key, String cipherText) {
try {
Key decryptionKey = new SecretKeySpec(key.getEncoded(),
key.getAlgorithm());
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
byte[] cipherTextBytes = hexToBytes(cipherText);
byte[] plainText;
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, ivSpec);
plainText = new byte[cipher.getOutputSize(cipherTextBytes.length)];
int decryptLength = cipher.update(cipherTextBytes, 0,
cipherTextBytes.length, plainText, 0);
decryptLength += cipher.doFinal(plainText, decryptLength);
return new String(plainText, "UTF-8");
} catch (NoSuchAlgorithmException | NoSuchProviderException
| NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException
| IllegalBlockSizeException | BadPaddingException
| ShortBufferException | UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
public static String bytesToHex(byte[] data, int length) {
String digits = "0123456789ABCDEF";
StringBuffer buffer = new StringBuffer();
for (int i = 0; i != length; i++) {
int v = data[i] & 0xff;
buffer.append(digits.charAt(v >> 4));
buffer.append(digits.charAt(v & 0xf));
}
return buffer.toString();
}
public static String bytesToHex(byte[] data) {
return bytesToHex(data, data.length);
}
public static byte[] hexToBytes(String string) {
int length = string.length();
byte[] data = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
data[i / 2] = (byte) ((Character.digit(string.charAt(i), 16) << 4) + Character
.digit(string.charAt(i + 1), 16));
}
return data;
}
我有一种感觉,我没有正确生成 ECDH
key (可能是由于我选择的命名曲线),但除此之外,我很困惑。谁能看到我可能做错了什么?
编辑:几乎忘记了输出的其余部分:
Original plaintext message: Look mah, I'm a message!
Private key length: 1106
Public key length: 158
Private key length: 1107
Public key length: 158
Shared key length: 66
0147A5780737C5C0D7457C503D4036AC7BBED53D5536A32D6BE8713E6DB4FE0A549AF20514C223D630426292A8EDB512EBD50726A130FFA4AEE96A0EC2A6F9D4C3A0
Shared key length: 66
0147A5780737C5C0D7457C503D4036AC7BBED53D5536A32D6BE8713E6DB4FE0A549AF20514C223D630426292A8EDB512EBD50726A130FFA4AEE96A0EC2A6F9D4C3A0
最佳答案
我对此进行了调查,我认为这是 BC 提供商的一个错误,或者可能是两个错误。
如果您选择基于 KDF 的算法并使用 OID 来识别生成 key 的 AES 算法,则可以使示例正常工作:
...
KeyAgreement keyAgreement = KeyAgreement.getInstance(X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme.getId(), "BC");
...
SecretKey key = keyAgreement.generateSecret(NISTObjectIdentifiers.id_aes128_CBC.getId());
...
或者,您可以通过将原始 66 字节 SecretKey 截断为 16(取前导字节,即 0 到 15)来解决此问题,因为这是它应该做的事情,但没有这样做。
我们将看看如何在 BC 解决这个问题。
关于java - 未在 Java 中使用 ECDH KeyAgreement 生成正确的 AES key 大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20260097/