gpt4 book ai didi

java - 未在 Java 中使用 ECDH KeyAgreement 生成正确的 AES key 大小

转载 作者:行者123 更新时间:2023-12-01 13:47:23 26 4
gpt4 key购买 nike

我希望能够根据 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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com