首页 文章

在Golang中解密用Java加密的内容(没有iv)

提问于
浏览
-3

Wenn我尝试解密用Java加密的字符串我得到一个错误:"cipher: message authentication failed" .

来自AESCipher.engineDoFinal(byte [] input,int inputOffset,int inputLen)的java inputOffset是否与我的代码中的Go nonceSize相同?

对于我的问题,“NewGCMWithNonceSize”是一个合适的解码器吗?

感谢帮助 . Working solution:

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
 }

1 回答

  • -1

    As noted in the comments to the question the follwing code is not secure since it uses the ECB mode of operation for encryption which should not be considered secure.


    问题是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 中的一个块解密为 result ,如documentation中所述 . 另请注意,循环迭代之间的增量是AES密码的块大小 .

    最后一个块可能包含填充,您仍需要删除 .

相关问题