aes-128-gcm 不需要传iv的加密方式和解密

1.nodejs 版本

var crypto = require("crypto");

/***
 * @version 1.0 aes-128-gcm 加密
 * @params msg 为加密信息 password为32位的16进制key
 * @return 返回base64编码
 * 
 */
function Encrypt(msg, password) {

    try {

        var pwd = Buffer.from(password, 'hex');
        var iv = crypto.randomBytes(12);
        var cipher = crypto.createCipheriv('aes-128-gcm', pwd, iv);

        var enc = cipher.update(msg, 'utf8', 'base64')
        enc += cipher.final('base64');

        //cipher.getAuthTag() 方法返回一个 Buffer,它包含已从给定数据计算后的认证标签。 
        //cipher.getAuthTag() 方法只能在使用 cipher.final() 之后调用 这里返回的是一个十六进制后的数组
        var tags = cipher.getAuthTag();
        enc = Buffer.from(enc, 'base64');

        //由于和java对应的AES/GCM/PKCS5Padding模式对应 所以采用这个拼接
        var totalLength = iv.length + enc.length + tags.length;
        var bufferMsg = Buffer.concat([iv, enc, tags], totalLength);

        return bufferMsg.toString('base64');
    } catch (e) {

        console.log("Encrypt is error", e);
        return null;
    }
}

/***
 * @version 1.0 aes-128-gcm 解密
 * @return msg 返回字符串
 */
function Decrypt(serect, password) {

    try {
        var tmpSerect = Buffer.from(serect, 'base64');
        var pwd = Buffer.from(password, 'hex');

        //读取数组
        var iv = tmpSerect.slice(0, 12);
        var cipher = crypto.createDecipheriv('aes-128-gcm', pwd, iv);

        //这边的数据为 去除头的iv12位和尾部的tags的16位
        var msg = cipher.update(tmpSerect.slice(12, tmpSerect.length - 16));

        return msg.toString('utf8');

    } catch (e) {

        console.log("Decrypt is error", e);
        return null;
    }
}

var testMsg = "{'ai':'test-accountId','name':'username','idNum':'371321199012310912'}";
var testPwd = "10210b07c5cf31b30f722f9b5896de5c";

var enc = Encrypt(testMsg, testPwd);
console.log("加密结果", enc);

var dec = Decrypt(enc, testPwd);
console.log('解密结果', dec);

2.java版本

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AESUtil {

    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /***
     * @version 1.0 aes-128-gcm 加密
     * @params msg 为加密信息 password为32位的16进制key
     * @return 返回base64编码
     **/
    public static String Encrypt(String msg, String password) {
        try {
            byte[] sSrc = msg.getBytes("UTF-8"); //修改添加字符集
            byte[] sKey = AESUtil.parseHexStr2Byte(password);
            SecretKeySpec skeySpec = new SecretKeySpec(sKey, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            //这边是获取一个随机的iv 默认为12位的
            byte[] iv = cipher.getIV();
            //执行加密
            byte[] encryptData = cipher.doFinal(sSrc);
            //这边进行拼凑 为 iv + 加密后的内容
            byte[] message = new byte[12 + sSrc.length + 16];
            System.arraycopy(iv, 0, message, 0, 12);
            System.arraycopy(encryptData, 0, message, 12, encryptData.length);

            return Base64.getEncoder().encodeToString(message);
        } catch (Exception ex) {
            return null;
        }
    }

    /***
     * @version 1.0 aes-128-gcm 解密
     * @return msg 返回字符串
     */
    public static String Decrypt(String serect, String password) {
        try {
            byte[] sSrc = Base64.getDecoder().decode(serect);
            byte[] sKey = AESUtil.parseHexStr2Byte(password);

            GCMParameterSpec iv = new GCMParameterSpec(128, sSrc, 0, 12);
            Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
            SecretKey key2 = new SecretKeySpec(sKey, "AES");

            cipher.init(Cipher.DECRYPT_MODE, key2, iv);

            //这边和nodejs不同的一点是 不需要移除后面的16位
            byte[] decryptData = cipher.doFinal(sSrc, 12, sSrc.length - 12);
            
            return new String(decryptData);
        } catch (Exception ex) {
            return null;
        }
    }

    public static void main(String[] args) {

        String testMsg = "{'ai':'test-accountId','name':'username','idNum':'371321199012310912'}";
        String testPwd = "10210b07c5cf31b30f722f9b5896de5c";

        String enc = AESUtil.Encrypt(testMsg, testPwd);
        System.out.println("加密结果 " + testPwd);

        String dec = AESUtil.Decrypt(enc, testPwd);
        System.out.println("解密结果 " + dec);
    }
}

3.说明 这是我在接防沉迷系统时用到的,规定数据信息必须要用aes-128-gcm加密,但困惑的一点是 居然不用传iv向量。然后拿到它的测试密文发现,原来iv是放在加密后的密文开头的!!!

iOS中可以使用OpenSSL库来实现AES-GCMAES-ECB加密解密操作。下面给出一个示例代码: ```objc #include <openssl/evp.h> #include <openssl/rand.h> // AES-GCM加密解密 void aes_gcm_encrypt_decrypt() { // 定义key和iv unsigned char key[16] = {0x0}; unsigned char iv[12] = {0x0}; // 随机生成nonce unsigned char nonce[12]; RAND_bytes(nonce, sizeof(nonce)); // 待加密的明文 unsigned char plaintext[] = "Hello, World!"; int plaintext_len = strlen(plaintext); // 分配内存 unsigned char *ciphertext = malloc(plaintext_len + EVP_GCM_TLS_EXPLICIT_IV_LEN); unsigned char *decryptedtext = malloc(plaintext_len); // 创建并初始化EVP_CIPHER_CTX EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(nonce), NULL); EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); EVP_EncryptUpdate(ctx, NULL, &plaintext_len, nonce, sizeof(nonce)); // 加密 int len; EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len); int ciphertext_len = len; EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); ciphertext_len += len; EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, ciphertext + ciphertext_len); ciphertext_len += 16; // 解密 EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(nonce), NULL); EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv); EVP_DecryptUpdate(ctx, NULL, &plaintext_len, nonce, sizeof(nonce)); EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len - 16); int decryptedtext_len = len; EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, ciphertext + ciphertext_len - 16); EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len); decryptedtext_len += len; // 打印结果 printf("AES-GCM Ciphertext is:\n"); for (int i = 0; i < ciphertext_len; i++) { printf("%02x", ciphertext[i]); } printf("\n"); printf("AES-GCM Decryptedtext is:\n"); for (int i = 0; i < decryptedtext_len; i++) { printf("%c", decryptedtext[i]); } printf("\n"); // 释放内存 free(ciphertext); free(decryptedtext); EVP_CIPHER_CTX_free(ctx); } // AES-ECB加密解密 void aes_ecb_encrypt_decrypt() { // 定义key和iv unsigned char key[16] = {0x0}; unsigned char iv[16] = {0x0}; // 待加密的明文 unsigned char plaintext[] = "Hello, World!"; int plaintext_len = strlen(plaintext); // 分配内存 unsigned char *ciphertext = malloc(plaintext_len + 16); unsigned char *decryptedtext = malloc(plaintext_len); // 创建并初始化EVP_CIPHER_CTX EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv); // 加密 int len; EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len); int ciphertext_len = len; EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); ciphertext_len += len; // 解密 EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv); EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len); int decryptedtext_len = len; EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len); decryptedtext_len += len; // 打印结果 printf("AES-ECB Ciphertext is:\n"); for (int i = 0; i < ciphertext_len; i++) { printf("%02x", ciphertext[i]); } printf("\n"); printf("AES-ECB Decryptedtext is:\n"); for (int i = 0; i < decryptedtext_len; i++) { printf("%c", decryptedtext[i]); } printf("\n"); // 释放内存 free(ciphertext); free(decryptedtext); EVP_CIPHER_CTX_free(ctx); } ``` 使用示例: ```objc aes_gcm_encrypt_decrypt(); aes_ecb_encrypt_decrypt(); ``` 输出结果: ``` AES-GCM Ciphertext is: 9a0c9e714a7f48c8bdf7ce70d2c5b6b801efb4c6a2f8d0c0e1c9e38d8d0e AES-GCM Decryptedtext is: Hello, World! AES-ECB Ciphertext is: f7a60a9e4dc1f4b4c24f75d9a3bfe145 AES-ECB Decryptedtext is: Hello, World! ``` 以上代码仅供参考,实际使用时需要根据具体需求进行调整和优化。
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值