我尝试解密用Java加密的字符串,但出现错误:“密码:消息身份验证失败” 。
来自 AESCipher.engineDoFinal(byte [] input,int inputOffset,int inputLen)的Java inputOffset 的含义与Go nonceSize 相同在我的代码中?
“ NewGCMWithNonceSize ”是否适合我的问题?
感谢您的帮助。 工作解决方案:
JAVA
public static String encryptGCM(String data) throws CryptException {
try {
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] iv = new byte[12];
random.nextBytes(iv);
log.trace("IV: {}", Arrays.toString(iv));
Key key = generateGcmKey();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] cipherText = cipher.doFinal(data.getBytes("UTF-8"));
log.trace("encrypted: {}", Arrays.toString(cipherText));
byte[] result = new byte[cipherText.length + iv.length];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(cipherText, 0, result, iv.length, cipherText.length);
log.trace("Not encoded result: {}", Arrays.toString(result));
return Base64.getEncoder().encodeToString(result);
} catch (Exception ex) {
log.error("Failure occured while encrypt text value!", ex);
throw new CryptException(data, ex);
}
}
private static Key generateGcmKey() throws CryptException {
try {
SecretKey originalKey = new SecretKeySpec(KEY.getBytes(), 0, KEY.getBytes().length, ALGO);
log.trace("Encoded key: {}", Base64.getEncoder().encodeToString(originalKey.getEncoded()));
return originalKey;
} catch (Exception ex) {
log.error("Failure occured while generate key!", ex);
throw new CryptException("Failure occured while generate key!", ex);
}
}
GO
func decode(data string) (string, error) {
ciphertext, _ := base64.StdEncoding.DecodeString(data)
key, _ := base64.URLEncoding.DecodeString(decodeKey)
c, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return "", err
}
nonceSize := 12
if len(ciphertext) < nonceSize {
return "", errors.New("ciphertext too short")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
result, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return "", err
}
return string(result), nil
}
答案 0 :(得分:0)
正如对该问题的评论所述,以下代码不安全,因为它使用ECB mode of operation进行加密,因此不应视为安全。
问题是GCM希望基础加密数据包含身份验证信息。 您的Java实现未提供此信息。
相反,您可以直接使用创建的AES密码来循环遍历消息的块。 看起来可能像这样:
func decode(data string) (string, error) {
ciphertext, err := base64.StdEncoding.Decode(data)
if err != nil {
return "", err
}
c, err := aes.NewCipher([]byte(DECODE_KEY))
if err != nil {
return "", err
}
result := make([]byte, len(ciphertext))
for i := 0; i < len(ciphertext); i += aes.BlockSize {
c.Decrypt(result[i:], ciphertext[i:])
}
return string(result), nil
}
每次调用c.Decrypt
都会将ciphertext
中的一个块解密为documentation中所述的result
。
还要注意,循环迭代之间的增量是AES密码的块大小。
最后一块可能包含填充,您仍然需要删除该填充。