首页 > 解决方案 > AES 256 GCM Java 实现

问题描述

我正在尝试将以下 AES-256-GCM 加密实现从 NodeJS 重写为 Java。

包描述

我得到了不同的输出,特别是 auth 标签部分。从它的外观来看,Java 库没有任何方法来获取 auth 标记,并且我尝试从输出中对其进行子串化失败。此外,我实际上不确定第一次使用公钥的 AES 加密(为 GCM 生成随机缓冲区)是否与 NodeJS 对应项相同。谁能指出我正确的方向?

节点JS:

public encryptPassword(password: string, encryptionKey: string, encryptionKeyId: string): { time: string, encrypted: string } {
    const randKey = crypto.randomBytes(32);
    const iv = crypto.randomBytes(12);
    const rsaEncrypted = crypto.publicEncrypt({
      key: Buffer.from(encryptionKey, 'base64').toString(),
      // @ts-ignore
      padding: crypto.constants.RSA_PKCS1_PADDING,
    }, randKey);
    const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv);
    const time = Math.floor(Date.now() / 1000).toString();
    cipher.setAAD(Buffer.from(time));
    const aesEncrypted = Buffer.concat([cipher.update(password, 'utf8'), cipher.final()]);
    const sizeBuffer = Buffer.alloc(2, 0);
    sizeBuffer.writeInt16LE(rsaEncrypted.byteLength, 0);
    const authTag = cipher.getAuthTag();
    return {
      time,
      encrypted: Buffer.concat([
        Buffer.from([1, encryptionKeyId]),
        iv,
        sizeBuffer,
        rsaEncrypted, authTag, aesEncrypted])
        .toString('base64'),
    };
  }

爪哇:

 private static Pair<Long, String> encryptPaswword(String password, String encryptionPubKey, String encryptionKeyId) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidCipherTextException, InvalidAlgorithmParameterException {
    byte[] passwordAsByte = password.getBytes();
    String decoededPubKey = new String(Base64.decode(encryptionPubKey, Base64.NO_WRAP), StandardCharsets.UTF_8);
    decoededPubKey = decoededPubKey.replace("-----BEGIN PUBLIC KEY-----", "");
    decoededPubKey = decoededPubKey.replace("-----END PUBLIC KEY-----", "");

    SecureRandom random = new SecureRandom();
    byte[] randKey = new byte[32];
    random.nextBytes(randKey);
    byte[] iv = new byte[12];
    random.nextBytes(iv);
    long date = new Date().getTime() / 1000;

    ByteBuffer header = ByteBuffer.allocate(2);
    header.put(Integer.valueOf(1).byteValue());
    header.put(Integer.valueOf(Integer.parseInt(encryptionKeyId)).byteValue());
    ByteBuffer timeAAD = ByteBuffer.allocate(10);
    timeAAD.put(String.valueOf(date).getBytes());

    X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(decoededPubKey, Base64.NO_WRAP));
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey publicKey = keyFactory.generatePublic(publicSpec);
    Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
    rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] rsaEncrypted = rsaCipher.doFinal(randKey);

    ByteBuffer sizeBuff = ByteBuffer.allocate(2);
    sizeBuff.put(Integer.valueOf(rsaEncrypted.length).byteValue());

    final Cipher gcmCipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec parameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
    gcmCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(randKey, "AES"), parameterSpec);
    gcmCipher.updateAAD(timeAAD);
    byte[] gcmText= gcmCipher.doFinal(passwordAsByte);

    ByteBuffer result = ByteBuffer.allocate(2+12+2+256+gcmText.length);
    result.put(header);
    result.put(iv);
    result.put(sizeBuff);
    result.put(rsaEncrypted);
    result.put(Arrays.copyOfRange(gcmText, gcmText.length - (16 / Byte.SIZE), gcmText.length));
    result.put(Arrays.copyOfRange(gcmText, 0, gcmText.length - (16 / Byte.SIZE)));

    return new Pair(new Long(date), Base64.encodeToString(result.array(), Base64.NO_WRAP));

标签: javaencryptionaescryptojsaes-gcm

解决方案


推荐阅读