美文网首页
AES-GCM模式代码演示

AES-GCM模式代码演示

作者: 滨岩 | 来源:发表于2022-12-19 00:20 被阅读0次

    对称加密与加密模式相关API

    image.png

    代码演示

    GCMAes

    package com.deepway.cryptology;
    
    import javax.crypto.Cipher;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.GCMParameterSpec;
    import java.security.*;
    
    /**
     * AES-GCM 
     * @author huyanbing
     * @create 2022/12/18 1:40 下午
     */
    public class GCMAes extends BaseCipher {
    
    
        // AES-GCM parameters
        /**
         * The length in bytes of IV
         * ivLen>=1
         * But 96-bit IV  values is recommended
         */
        // 12 bytes
        private static final int GCM_NONCE_LENGTH = 96 >> 3;
    
    
        /**
         * The length
         * in bits
         * of Tag <code>T</code>;
         * tLen must
         * be one  of {
         * 128, 120, 112, 104, 96
         * }
         * <p>
         * GCM tag 长度 我们一般取最长 128 也是比较推荐的
         */
        private static final int GCM_TAG_LENGTH = 128;// 16 bytes
    
    
        private Cipher cipher;
    
        //GCM的 IV 比较特殊
        private GCMParameterSpec iv;
    
    
        /**
         * 构造函数
         *
         * @param keyLen
         * @param plainKey
         */
        public GCMAes(int keyLen, byte[] plainKey) {
            super(keyLen, plainKey);
        }
    
    
        /**
         * 初始化
         *
         * @param mode
         * @param nonce
         * @throws GeneralSecurityException
         */
        public void initialize(int mode, byte[] nonce) throws GeneralSecurityException {
            //如果用户没有给 nonce随机数的值,就自己生产初始化的随机值
            if (nonce == null) {
                nonce = new byte[GCM_NONCE_LENGTH];
                new SecureRandom().nextBytes(nonce);
            }
            //构造GCMParameterSpec
            //一个是 tag 长度 ,一个是初始化向量随机数 nonce  然后构成出IV
            //GCM模式只能使用GCMParameterSpec
            iv = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
    
            try {
                this.cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
    
                //3-args  初始化 三个参数  mode(加密模式、解密模式)  key:密钥  iv:初始向量
                this.cipher.init(mode, key, iv);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * 加密
         * <p>
         * <p>
         * 两个参数 Input  消息本体
         * aad 附加认证数据 aad 数据
         *
         * @param input
         * @param aad
         * @return
         * @throws Exception
         */
        public byte[] encrypt(byte[] input, byte[] aad) throws Exception {
            //first aad
            if (aad != null) {
                //如果有aad 认证数据,需要先添加aad认证数据,然后才能加密消息本体数据
                cipher.updateAAD(aad);
            }
            // cipher.update(input);
            //如果 input 很小,直接调用cipher.doFinal(input) 就可以了
            //jdk9 返回的   gcm->cipher-text,Tag  两个值 一个是加密密文,一个是认证的 128位的tag
            return cipher.doFinal(input);
        }
    
    
        public static void main(String[] args) throws Exception {
    
            byte[] plainText = "Hello AES-GCM  ..11111111111111111111".getBytes();
    
            System.out.println("GCM plaintText:");
    
            System.out.println(new String(plainText));
    
    
            byte[] aad = "My name is Bob".getBytes();
    
            GCMAes gcmAlice = new GCMAes(128, null);
            gcmAlice.initialize(Cipher.ENCRYPT_MODE, null);
            byte[] cipherText = gcmAlice.encrypt(plainText, aad);
            System.out.println("GCM cipher:");
            System.out.println(HexCustomUtil.bytes2hex(cipherText));
    //
    //        {
    //            //for RPC ,serializing,persistence
    //            new Object() {
    //                byte[] aad;
    //                byte[] iv;
    //                byte[] cipherText;
    //            };
    //        }
    
            GCMAes gcmBob = new GCMAes(128, gcmAlice.exportKey());
    
            gcmBob.initialize(Cipher.DECRYPT_MODE, gcmAlice.iv.getIV());
    
            byte[] plainText2 = gcmBob.encrypt(cipherText, aad);
    
            System.out.println("GCM plaintText:");
    
            System.out.println(new String(plainText2));
    
        }
    
    
    }
    
    

    BaseCipher

    package com.deepway.cryptology;
    
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.NoSuchAlgorithmException;
    
    /**
     * @author huyanbing
     * @create 2022/12/17 6:44 下午
     */
    public class BaseCipher {
    
    
        private final int keyLen;
        protected final SecretKey key;
    
        private String algorithm = "AES";
    
        /**
         * 构造函数
         *
         * @param keyLen
         * @param plainKey
         */
        public BaseCipher(int keyLen, byte[] plainKey) {
            //验证密钥长度是不是合规的
            assert keyLen == 128 || keyLen == 192 || keyLen == 256;
            this.keyLen = keyLen;
            if (plainKey == null) {
                key = generateKey();
            } else {
                key = importKey(plainKey);
            }
        }
    
    
        /**
         * 生成默认密钥
         *
         * @return
         */
        public SecretKey generateKey() {
    
            try {
                //静态工厂模式
                KeyGenerator keyGen = KeyGenerator.getInstance(algorithm);
                keyGen.init(keyLen);
    
                SecretKey key = keyGen.generateKey();
                return key;
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }
    
    
        /**
         * 导出密钥
         *
         * @return
         */
        public byte[] exportKey() {
            return key.getEncoded();
        }
    
    
        /**
         * 导入密钥
         *
         * @param plainKey
         * @return
         */
        public SecretKey importKey(byte[] plainKey) {
    
    
            //=>  keyLen/8
            assert plainKey.length == keyLen >> 3;
    
            return new SecretKeySpec(plainKey, algorithm);
        }
    
    }
    
    

    package com.deepway.cryptology;
    
    /**
     * @author huyanbing
     * @create 2022/12/16 3:29 下午
     */
    public class HexCustomUtil {
    
        /*输入16进制byte[]输出16进制字符串*/
        public static String byteArrayToHexStr(byte[] byteArray) {
            if (byteArray == null) {
                return null;
            }
            char[] hexArray = "0123456789ABCDEF".toCharArray();
            char[] hexChars = new char[byteArray.length * 2];
            for (int j = 0; j < byteArray.length; j++) {
                int v = byteArray[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        }
    
    
        public static String bytes2hex(byte[] bytes) {
            StringBuilder sb = new StringBuilder();
            String tmp;
            sb.append("[");
            for (byte b : bytes) {
                // 将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制
                tmp = Integer.toHexString(0xFF & b);
                if (tmp.length() == 1) {
                    tmp = "0" + tmp;//只有一位的前面补个0
                }
                sb.append(tmp).append(" ");//每个字节用空格断开
            }
            sb.delete(sb.length() - 1, sb.length());//删除最后一个字节后面对于的空格
            sb.append("]");
            return sb.toString();
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:AES-GCM模式代码演示

          本文链接:https://www.haomeiwen.com/subject/jwfsqdtx.html