美文网首页
常用加密算法

常用加密算法

作者: 策马踏清风 | 来源:发表于2020-09-15 11:36 被阅读0次

    一、分类

    • 对称加密:DES3DESAES等(安全等级中,速度很快,每秒数M比特)
    • 非对称加密:RSADSA等(安全等级高,速度比较慢,适合小数据量或数据签名)
    • 散列算法:SHA-1MD5

    二、散列

    2.1 MD5

    • 使用哈希函数,对信息进行摘要
    • 无论多长,都会输出一个长度为128bits的串(通常用 16 进制 表示为 32 个字符)
    public static final byte[] computeMD5(byte[] content) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            return md5.digest(content);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    

    2.2 SHA1算法

    • 相对于MD5更安全
    • 对于长度小于2^64位的消息,会产生一个160位的信息摘要
    public static byte[] computeSHA1(byte[] content) {
        try {
            MessageDigest sha1 = MessageDigest.getInstance("SHA1");
            return sha1.digest(content);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    

    2.3 HMAC算法

    • 相当于对称加密+散列
    • 发送发通过密钥和原文计算出加密的散列,接收方也需要通过原文密钥解密得到正确的散列
    • 多个线程同时使用一个实例会导致线程不安全的问题,需要加锁或者使用ThreadLocal
    @NotThreadSafe
    public class HMacHelper {
        private static final Logger logger = LoggerFactory.getLogger(HMacHelper.class);
        private Mac mac;
    
        /**
         * MAC算法可选以下多种算法
         * HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512
         */
        private static final String KEY_MAC = "HmacMD5";
        public HMacHelper(String key) {
            try {
                SecretKey secretKey = new SecretKeySpec(key.getBytes(ConstField.UTF8), KEY_MAC);
                mac = Mac.getInstance(secretKey.getAlgorithm());
                mac.init(secretKey);
            } catch (Exception e) {
                logger.error("create hmac helper failed.", e);
            }
        }
        public byte[] sign(byte[] content) {
            return mac.doFinal(content);
        }
    
        public boolean verify(byte[] signature, byte[] content) {
            try {
                byte[] result = mac.doFinal(content);
                return Arrays.equals(signature, result);
            } catch (Exception e) {
                logger.error("verify sig failed.", e);
            }
            return false;
        }
    }
    

    三、对称加密

    3.1 AES

    • 高级别的加密标准,区块加密标准
    • 对称分组密码机制
    • 分组密码,128位是一个分组。
    • 秘钥长度最少支持为128位、192位、256
    @NotThreadSafe
    public class AesHelper {
        private SecretKeySpec keySpec;
        private IvParameterSpec iv;
    
        public AesHelper(byte[] aesKey, byte[] iv) {
            if (aesKey == null || aesKey.length < 16 || (iv != null && iv.length < 16)) {
                throw new RuntimeException("错误的初始密钥");
            }
            if (iv == null) {
                iv = Md5Util.compute(aesKey);
            }
            keySpec = new SecretKeySpec(aesKey, "AES");
            this.iv = new IvParameterSpec(iv);
        }
    
        public AesHelper(byte[] aesKey) {
            if (aesKey == null || aesKey.length < 16) {
                throw new RuntimeException("错误的初始密钥");
            }
            keySpec = new SecretKeySpec(aesKey, "AES");
            this.iv = new IvParameterSpec(Md5Util.compute(aesKey));
        }
    
        public byte[] encrypt(byte[] data) {
            byte[] result = null;
            Cipher cipher = null;
            try {
                cipher = Cipher.getInstance("AES/CFB/NoPadding");
                cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
                result = cipher.doFinal(data);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return result;
        }
    
        public byte[] decrypt(byte[] secret) {
            byte[] result = null;
            Cipher cipher = null;
            try {
                cipher = Cipher.getInstance("AES/CFB/NoPadding");
                cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
                result = cipher.doFinal(secret);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return result;
        }
    
        public static byte[] randomKey(int size) {
            byte[] result = null;
            try {
                KeyGenerator gen = KeyGenerator.getInstance("AES");
                gen.init(size, new SecureRandom());
                result = gen.generateKey().getEncoded();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return result;
        }
    }
    

    四、非对称加密

    4.1 RSA

    • 目前最有影响力的公钥加密算法,可同时用于加密和数字签名
    • 能抵抗已知所有的密码攻击
    @NotThreadSafe
    public class RsaHelper {
        private static final Logger logger = LoggerFactory.getLogger(RsaHelper.class);
        private RSAPublicKey publicKey;
        private RSAPrivateCrtKey privateKey;
    
        static {
            Security.addProvider(new BouncyCastleProvider()); //使用bouncycastle作为加密算法实现
        }
    
        public RsaHelper(String publicKey, String privateKey) {
            this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
        }
    
        public RsaHelper(byte[] publicKey, byte[] privateKey) {
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                if (publicKey != null && publicKey.length > 0) {
                    this.publicKey = (RSAPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
                }
                if (privateKey != null && privateKey.length > 0) {
                    this.privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public RsaHelper(String publicKey) {
            this(Base64Util.decode(publicKey));
        }
    
        public RsaHelper(byte[] publicKey) {
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                if (publicKey != null && publicKey.length > 0) {
                    this.publicKey = (RSAPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public byte[] encrypt(byte[] content) {
            if (publicKey == null) {
                throw new RuntimeException("public key is null.");
            }
    
            if (content == null) {
                return null;
            }
    
            try {
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                int size = publicKey.getModulus().bitLength() / 8 - 11;
                ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 11));
                int left = 0;
                for (int i = 0; i < content.length; ) {
                    left = content.length - i;
                    if (left > size) {
                        cipher.update(content, i, size);
                        i += size;
                    } else {
                        cipher.update(content, i, left);
                        i += left;
                    }
                    baos.write(cipher.doFinal());
                }
                return baos.toByteArray();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public byte[] decrypt(byte[] secret) {
            if (privateKey == null) {
                throw new RuntimeException("private key is null.");
            }
    
            if (secret == null) {
                return null;
            }
    
            try {
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                int size = privateKey.getModulus().bitLength() / 8;
                ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size - 12) / (size - 11) * size);
                int left = 0;
                for (int i = 0; i < secret.length; ) {
                    left = secret.length - i;
                    if (left > size) {
                        cipher.update(secret, i, size);
                        i += size;
                    } else {
                        cipher.update(secret, i, left);
                        i += left;
                    }
                    baos.write(cipher.doFinal());
                }
                return baos.toByteArray();
            } catch (Exception e) {
                logger.error("rsa decrypt failed.", e);
            }
            return null;
        }
    
        public byte[] sign(byte[] content) {
            if (privateKey == null) {
                throw new RuntimeException("private key is null.");
            }
            if (content == null) {
                return null;
            }
            try {
                Signature signature = Signature.getInstance("SHA1WithRSA");
                signature.initSign(privateKey);
                signature.update(content);
                return signature.sign();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public boolean verify(byte[] sign, byte[] content) {
            if (publicKey == null) {
                throw new RuntimeException("public key is null.");
            }
            if (sign == null || content == null) {
                return false;
            }
            try {
                Signature signature = Signature.getInstance("SHA1WithRSA");
                signature.initVerify(publicKey);
                signature.update(content);
                return signature.verify(sign);
            } catch (Exception e) {
                logger.error("rsa verify failed.", e);
            }
            return false;
        }
    }
    

    相关文章

      网友评论

          本文标题:常用加密算法

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