加密算法_加密算法总结 - CSDN
加密算法 订阅
数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的密钥之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。通过修改文件的md5值,可以绕过某些网盘的"违规文件扫描机制",这是因为网盘服务器内存储着已知违规文件的md5值,当上传文件时会自动与服务器md5数据库匹配以判断是否违规。 [1] 展开全文
数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的密钥之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。通过修改文件的md5值,可以绕过某些网盘的"违规文件扫描机制",这是因为网盘服务器内存储着已知违规文件的md5值,当上传文件时会自动与服务器md5数据库匹配以判断是否违规。 [1]
信息
别    称
密文
作    用
加密数据 [2]
解    锁
密钥
中文名
加密算法
外文名
Encryption algorithm
加密算法相关简介
据记载,公元前400年,古希腊人发明了置换密码。1881年世界上的第一个电话保密专利出现。在第二次世界大战期间,德国军方启用“恩尼格玛”密码机,密码学在战争中起着非常重要的作用。随着信息化和数字化社会的发展,人们对信息安全和保密的重要性认识不断提高,于是在1997年,美国国家标准局公布实施了“美国数据加密标准(DES)”,民间力量开始全面介入密码学的研究和应用中,采用的加密算法有DES、RSA、SHA等。随着对加密强度需求的不断提高,近期又出现了AES、ECC等。使用密码学可以达到以下目的:保密性:防止用户的标识或数据被读取。数据完整性:防止数据被更改。身份验证:确保数据发自特定的一方。
收起全文
精华内容
参与话题
  • 几种加密算法

    千次阅读 2020-04-03 10:06:45
    1. AES 高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密...加密算法是一种典型的非对称加密算法,它基于大数的因式分解数学难题,它也是应用最广 泛的非对称加密算法。 非对称加密是通过两个...

    1. AES

    高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传
    输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下
     
     

    2. RSA RSA

    加密算法是一种典型的非对称加密算法,它基于大数的因式分解数学难题,它也是应用最广 泛的非对称加密算法。 非对称加密是通过两个密钥(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥用 于解密

    3. CRC

    循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或电脑文件等数据产生简 短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。 它是利用除法及余数的原理来作错误侦测的。

     

    4. MD5 

    常常作为文件的签名出现,我们在下载文件的时候,常常会看到文件页面上附带一个扩展 名为.MD5 的文本或者一行字符,这行字符就是就是把整个文件当作原数据通过 MD5 计算后的值, 我们下载文件后,可以用检查文件 MD5 信息的软件对下载到的文件在进行一次计算。两次结果对 比就可以确保下载到文件的准确性。 另一种常见用途就是网站敏感信息加密,比如用户名密码, 支付签名等等。随着 https 技术的普及,现在的网站广泛采用前台明文传输到后台,MD5 加密 (使用偏移量)的方式保护敏感数据保护站点和数据安全。

    展开全文
  • 数字签名、信息加密 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、oauth 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 签名加密算法来达到...

    1. 前言


    数字签名信息加密 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、oauth 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 签名加密算法来达到业务目标。这里简单的给大家介绍几种常见的签名加密算法和一些典型场景下的应用。

     

    2. 正文


    2.1 数字签名

    数字签名,简单来说就是通过提供 可鉴别 的 数字信息 验证 自身身份 的一种方式。一套 数字签名 通常定义两种 互补 的运算,一个用于 签名,另一个用于 验证。分别由 发送者 持有能够 代表自己身份 的 私钥 (私钥不可泄露),由 接受者 持有与私钥对应的 公钥 ,能够在 接受 到来自发送者信息时用于 验证 其身份。

    注意:图中 加密过程 有别于 公钥加密,更多 介绍戳这里。签名 最根本的用途是要能够唯一 证明发送方的身份,防止 中间人攻击CSRF 跨域身份伪造。基于这一点在诸如 设备认证用户认证第三方认证等认证体系中都会使用到 签名算法 (彼此的实现方式可能会有差异)。

    2.2 加密和解密

    2.2.1 加密

    数据加密 的基本过程,就是对原来为 明文 的文件或数据按 某种算法 进行处理,使其成为 不可读 的一段代码,通常称为 “密文”。通过这样的途径,来达到 保护数据 不被 非法人窃取、阅读的目的。

    2.2. 解密

    加密 的 逆过程 为 解密,即将该 编码信息 转化为其 原来数据 的过程。

    2.3 对称加密和非对称加密

    加密算法分 对称加密 和 非对称加密,其中对称加密算法的加密与解密 密钥相同,非对称加密算法的加密密钥与解密 密钥不同,此外,还有一类 不需要密钥 的 散列算法

    常见的 对称加密 算法主要有 DES3DESAES 等,常见的 非对称算法 主要有 RSADSA 等,散列算法主要有 SHA-1MD5 等。

    2.3.1 对称加密

    对称加密算法 是应用较早的加密算法,又称为 共享密钥加密算法。在 对称加密算法 中,使用的密钥只有一个,发送 和 接收 双方都使用这个密钥对数据进行 加密 和 解密。这就要求加密和解密方事先都必须知道加密的密钥。

    1. 数据加密过程:在对称加密算法中,数据发送方 将 明文 (原始数据) 和 加密密钥 一起经过特殊 加密处理,生成复杂的 加密密文 进行发送。

    2. 数据解密过程:数据接收方 收到密文后,若想读取原数据,则需要使用 加密使用的密钥 及相同算法的 逆算法 对加密的密文进行解密,才能使其恢复成 可读明文

    2.3.2 非对称加密

    非对称加密算法,又称为 公开密钥加密算法。它需要两个密钥,一个称为 公开密钥 (public key),即 公钥,另一个称为 私有密钥 (private key),即 私钥

    因为 加密 和 解密 使用的是两个不同的密钥,所以这种算法称为 非对称加密算法

    1. 如果使用 公钥 对数据 进行加密,只有用对应的 私钥 才能 进行解密

    2. 如果使用 私钥 对数据 进行加密,只有用对应的 公钥 才能 进行解密

    例子:甲方生成 一对密钥 并将其中的一把作为 公钥 向其它人公开,得到该公钥的 乙方 使用该密钥对机密信息 进行加密 后再发送给甲方,甲方再使用自己保存的另一把 专用密钥 (私钥),对 加密 后的信息 进行解密

    2.4 常见的签名加密算法

    2.4.1 MD5算法

    MD5 用的是 哈希函数,它的典型应用是对一段信息产生 信息摘要,以 防止被篡改。严格来说,MD5 不是一种 加密算法 而是 摘要算法。无论是多长的输入,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.4.2 SHA1算法

    SHA1 是和 MD5 一样流行的 消息摘要算法,然而 SHA1 比 MD5 的 安全性更强。对于长度小于 2 ^ 64 位的消息,SHA1 会产生一个 160 位的 消息摘要。基于 MD5SHA1 的信息摘要特性以及 不可逆 (一般而言),可以被应用在检查 文件完整性 以及 数字签名 等场景。

    public static byte[] computeSHA1(byte[] content) {
        try {
            MessageDigest sha1 = MessageDigest.getInstance("SHA1");
            return sha1.digest(content);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    

    2.4.3 HMAC算法

    HMAC 是密钥相关的 哈希运算消息认证码(Hash-based Message Authentication Code),HMAC 运算利用 哈希算法 (MD5SHA1 等),以 一个密钥 和 一个消息 为输入,生成一个 消息摘要 作为 输出

    HMAC 发送方 和 接收方 都有的 key 进行计算,而没有这把 key 的第三方,则是 无法计算 出正确的 散列值的,这样就可以 防止数据被篡改

    package net.pocrd.util;
    import net.pocrd.annotation.NotThreadSafe;
    import net.pocrd.define.ConstField;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import javax.crypto.Mac;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Arrays;
    
    
    @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;
        }
    }
    

    测试结论HMAC 算法实例在 多线程环境 下是 不安全的。但是需要在 多线程访问 时,进行同步的辅助类,使用 ThreadLocal 为 每个线程缓存 一个实例可以避免进行锁操作。

    2.4.4 AES/DES/3DES算法

    AESDES3DES 都是 对称 的 块加密算法加解密 的过程是 可逆的。常用的有 AES128AES192AES256 (默认安装的 JDK 尚不支持 AES256,需要安装对应的 jce 补丁进行升级 jce1.7jce1.8)。

    2.4.4.1 DES算法

    DES 加密算法是一种 分组密码,以 64 位为 分组对数据 加密,它的 密钥长度 是 56 位,加密解密 用 同一算法

    DES 加密算法是对 密钥 进行保密,而 公开算法,包括加密和解密算法。这样,只有掌握了和发送方 相同密钥 的人才能解读由 DES加密算法加密的密文数据。因此,破译 DES 加密算法实际上就是 搜索密钥的编码。对于 56 位长度的 密钥 来说,如果用 穷举法 来进行搜索的话,其运算次数为 2 ^ 56 次。

    2.4.4.2 3DES算法

    是基于 DES 的 对称算法,对 一块数据 用 三个不同的密钥 进行 三次加密强度更高

    2.4.4.3 AES算法

    AES 加密算法是密码学中的 高级加密标准,该加密算法采用 对称分组密码体制,密钥长度的最少支持为 128 位、 192 位、256 位,分组长度 128 位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的 区块加密标准

    AES 本身就是为了取代 DES 的,AES 具有更好的 安全性效率 和 灵活性

    import net.pocrd.annotation.NotThreadSafe;
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.SecureRandom;
    
    @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;
        }
    }
    

    2.4.5 RSA算法

    RSA 加密算法是目前最有影响力的 公钥加密算法,并且被普遍认为是目前 最优秀的公钥方案 之一。RSA 是第一个能同时用于 加密 和 数字签名 的算法,它能够 抵抗 到目前为止已知的 所有密码攻击,已被 ISO 推荐为公钥数据加密标准。

    RSA 加密算法 基于一个十分简单的数论事实:将两个大 素数 相乘十分容易,但想要对其乘积进行 因式分解 却极其困难,因此可以将 乘积 公开作为 加密密钥

    import net.pocrd.annotation.NotThreadSafe;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import javax.crypto.Cipher;
    import java.io.ByteArrayOutputStream;
    import java.security.KeyFactory;
    import java.security.Security;
    import java.security.Signature;
    import java.security.interfaces.RSAPrivateCrtKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    @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;
        }
    }
    

    2.4.6 ECC算法

    ECC 也是一种 非对称加密算法,主要优势是在某些情况下,它比其他的方法使用 更小的密钥,比如 RSA 加密算法,提供 相当的或更高等级 的安全级别。不过一个缺点是 加密和解密操作 的实现比其他机制 时间长(相比 RSA 算法,该算法对 CPU 消耗严重)。

    import net.pocrd.annotation.NotThreadSafe;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import javax.crypto.Cipher;
    import java.io.ByteArrayOutputStream;
    import java.security.KeyFactory;
    import java.security.Security;
    import java.security.Signature;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    @NotThreadSafe
    public class EccHelper {
        private static final Logger logger = LoggerFactory.getLogger(EccHelper.class);
        private static final int SIZE = 4096;
        private BCECPublicKey  publicKey;
        private BCECPrivateKey privateKey;
    
        static {
            Security.addProvider(new BouncyCastleProvider());
        }
    
        public EccHelper(String publicKey, String privateKey) {
            this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
        }
    
        public EccHelper(byte[] publicKey, byte[] privateKey) {
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
                if (publicKey != null && publicKey.length > 0) {
                    this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
                }
                if (privateKey != null && privateKey.length > 0) {
                    this.privateKey = (BCECPrivateKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
                }
            } catch (ClassCastException e) {
                throw new RuntimeException("", e);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public EccHelper(String publicKey) {
            this(Base64Util.decode(publicKey));
        }
    
        public EccHelper(byte[] publicKey) {
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
                if (publicKey != null && publicKey.length > 0) {
                    this.publicKey = (BCECPublicKey)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.");
            }
            try {
                Cipher cipher = Cipher.getInstance("ECIES", "BC");
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                int size = SIZE;
                ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 45));
                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.");
            }
            try {
                Cipher cipher = Cipher.getInstance("ECIES", "BC");
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                int size = SIZE + 45;
                ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size + 44) / (size + 45) * 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("ecc decrypt failed.", e);
            }
            return null;
        }
    
        public byte[] sign(byte[] content) {
            if (privateKey == null) {
                throw new RuntimeException("private key is null.");
            }
            try {
                Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
                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.");
            }
            try {
                Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
                signature.initVerify(publicKey);
                signature.update(content);
                return signature.verify(sign);
            } catch (Exception e) {
                logger.error("ecc verify failed.", e);
            }
            return false;
        }
    }
    

    2.5 各种加密算法对比

    2.5.1 散列算法比较

    名称 安全性 速度
    SHA-1
    MD5

    2.5.2 对称加密算法比较

    名称 密钥名称 运行速度 安全性 资源消耗
    DES 56位 较快
    3DES 112位或168位
    AES 128、192、256位

    2.5.3 非对称加密算法比较

    名称 成熟度 安全性 运算速度 资源消耗
    RSA
    ECC

    2.5.4 对称算法与非对称加密算法

    2.5.4.1 对称算法

    1. 密钥管理:比较难,不适合互联网,一般用于内部系统

    2. 安全性:中

    3. 加密速度:快好 几个数量级 (软件加解密速度至少快 100 倍,每秒可以加解密数 M 比特 数据),适合大数据量的加解密处理

    2.5.4.2 非对称算法

    1. 密钥管理:密钥容易管理

    2. 安全性:高

    3. 加密速度:比较慢,适合 小数据量 加解密或数据签名

     

    3. 小结


    本文介绍了 数字签名加密和解密对称加密和非对称加密,然后详细介绍了 MD5SHA-1HMACDES/AESRSA 和 ECC 这几种加密算法和代码示例。

    展开全文
  • 浅谈常见的七种加密算法及实现

    万次阅读 多人点赞 2018-09-10 18:38:26
    数字签名、信息加密 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、oauth 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 签名加密算法 来达到业务...

    前言

    数字签名信息加密 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、oauth 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 签名加密算法 来达到业务目标。这里简单的给大家介绍几种常见的签名加密算法和一些典型场景下的应用。

    正文

    1. 数字签名

    数字签名,简单来说就是通过提供 可鉴别数字信息 验证 自身身份 的一种方式。一套 数字签名 通常定义两种 互补 的运算,一个用于 签名,另一个用于 验证。分别由 发送者 持有能够 代表自己身份私钥 (私钥不可泄露),由 接受者 持有与私钥对应的 公钥 ,能够在 接受 到来自发送者信息时用于 验证 其身份。

    注意:图中 加密过程 有别于 公钥加密,更多 介绍戳这里签名 最根本的用途是要能够唯一 证明发送方的身份,防止 中间人攻击CSRF 跨域身份伪造。基于这一点在诸如 设备认证用户认证第三方认证 等认证体系中都会使用到 签名算法 (彼此的实现方式可能会有差异)。

    2. 加密和解密

    2.1. 加密

    数据加密 的基本过程,就是对原来为 明文 的文件或数据按 某种算法 进行处理,使其成为 不可读 的一段代码,通常称为 “密文”。通过这样的途径,来达到 保护数据 不被 非法人窃取、阅读的目的。

    2.2. 解密

    加密逆过程解密,即将该 编码信息 转化为其 原来数据 的过程。

    3. 对称加密和非对称加密

    加密算法分 对称加密非对称加密,其中对称加密算法的加密与解密 密钥相同,非对称加密算法的加密密钥与解密 密钥不同,此外,还有一类 不需要密钥散列算法

    常见的 对称加密 算法主要有 DES3DESAES 等,常见的 非对称算法 主要有 RSADSA 等,散列算法 主要有 SHA-1MD5 等。

    3.1. 对称加密

    对称加密算法 是应用较早的加密算法,又称为 共享密钥加密算法。在 对称加密算法 中,使用的密钥只有一个,发送接收 双方都使用这个密钥对数据进行 加密解密。这就要求加密和解密方事先都必须知道加密的密钥。

    1. 数据加密过程:在对称加密算法中,数据发送方明文 (原始数据) 和 加密密钥 一起经过特殊 加密处理,生成复杂的 加密密文 进行发送。

    2. 数据解密过程:数据接收方 收到密文后,若想读取原数据,则需要使用 加密使用的密钥 及相同算法的 逆算法 对加密的密文进行解密,才能使其恢复成 可读明文

    3.2. 非对称加密

    非对称加密算法,又称为 公开密钥加密算法。它需要两个密钥,一个称为 公开密钥 (public key),即 公钥,另一个称为 私有密钥 (private key),即 私钥

    因为 加密解密 使用的是两个不同的密钥,所以这种算法称为 非对称加密算法

    1. 如果使用 公钥 对数据 进行加密,只有用对应的 私钥 才能 进行解密

    2. 如果使用 私钥 对数据 进行加密,只有用对应的 公钥 才能 进行解密

    例子:甲方生成 一对密钥 并将其中的一把作为 公钥 向其它人公开,得到该公钥的 乙方 使用该密钥对机密信息 进行加密 后再发送给甲方,甲方再使用自己保存的另一把 专用密钥 (私钥),对 加密 后的信息 进行解密

    4. 常见的签名加密算法

    4.1. MD5算法

    MD5 用的是 哈希函数,它的典型应用是对一段信息产生 信息摘要,以 防止被篡改。严格来说,MD5 不是一种 加密算法 而是 摘要算法。无论是多长的输入,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);
        }
    }

    4.2. SHA1算法

    SHA1 是和 MD5 一样流行的 消息摘要算法,然而 SHA1MD5安全性更强。对于长度小于 2 ^ 64 位的消息,SHA1 会产生一个 160 位的 消息摘要。基于 MD5SHA1 的信息摘要特性以及 不可逆 (一般而言),可以被应用在检查 文件完整性 以及 数字签名 等场景。

    public static byte[] computeSHA1(byte[] content) {
        try {
            MessageDigest sha1 = MessageDigest.getInstance("SHA1");
            return sha1.digest(content);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    4.3. HMAC算法

    HMAC 是密钥相关的 哈希运算消息认证码(Hash-based Message Authentication Code),HMAC 运算利用 哈希算法 (MD5SHA1 等),以 一个密钥一个消息 为输入,生成一个 消息摘要 作为 输出

    HMAC 发送方接收方 都有的 key 进行计算,而没有这把 key 的第三方,则是 无法计算 出正确的 散列值的,这样就可以 防止数据被篡改

    package net.pocrd.util;
    import net.pocrd.annotation.NotThreadSafe;
    import net.pocrd.define.ConstField;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import javax.crypto.Mac;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Arrays;
    
    
    @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;
        }
    }

    测试结论HMAC 算法实例在 多线程环境 下是 不安全的。但是需要在 多线程访问 时,进行同步的辅助类,使用 ThreadLocal每个线程缓存 一个实例可以避免进行锁操作。

    4.4. AES/DES/3DES算法

    AESDES3DES 都是 对称块加密算法加解密 的过程是 可逆的。常用的有 AES128AES192AES256 (默认安装的 JDK 尚不支持 AES256,需要安装对应的 jce 补丁进行升级 jce1.7jce1.8)。

    4.4.1. DES算法

    DES 加密算法是一种 分组密码,以 64 位为 分组对数据 加密,它的 密钥长度56 位,加密解密同一算法

    DES 加密算法是对 密钥 进行保密,而 公开算法,包括加密和解密算法。这样,只有掌握了和发送方 相同密钥 的人才能解读由 DES加密算法加密的密文数据。因此,破译 DES 加密算法实际上就是 搜索密钥的编码。对于 56 位长度的 密钥 来说,如果用 穷举法 来进行搜索的话,其运算次数为 2 ^ 56 次。

    4.4.2. 3DES算法

    是基于 DES对称算法,对 一块数据三个不同的密钥 进行 三次加密强度更高

    4.4.3. AES算法

    AES 加密算法是密码学中的 高级加密标准,该加密算法采用 对称分组密码体制,密钥长度的最少支持为 128 位、 192 位、256 位,分组长度 128 位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的 区块加密标准

    AES 本身就是为了取代 DES 的,AES 具有更好的 安全性效率灵活性

    import net.pocrd.annotation.NotThreadSafe;
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.SecureRandom;
    
    @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.5. RSA算法

    RSA 加密算法是目前最有影响力的 公钥加密算法,并且被普遍认为是目前 最优秀的公钥方案 之一。RSA 是第一个能同时用于 加密数字签名 的算法,它能够 抵抗 到目前为止已知的 所有密码攻击,已被 ISO 推荐为公钥数据加密标准。

    RSA 加密算法 基于一个十分简单的数论事实:将两个大 素数 相乘十分容易,但想要对其乘积进行 因式分解 却极其困难,因此可以将 乘积 公开作为 加密密钥

    import net.pocrd.annotation.NotThreadSafe;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import javax.crypto.Cipher;
    import java.io.ByteArrayOutputStream;
    import java.security.KeyFactory;
    import java.security.Security;
    import java.security.Signature;
    import java.security.interfaces.RSAPrivateCrtKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    @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;
        }
    }

    4.6. ECC算法

    ECC 也是一种 非对称加密算法,主要优势是在某些情况下,它比其他的方法使用 更小的密钥,比如 RSA 加密算法,提供 相当的或更高等级 的安全级别。不过一个缺点是 加密和解密操作 的实现比其他机制 时间长 (相比 RSA 算法,该算法对 CPU 消耗严重)。

    import net.pocrd.annotation.NotThreadSafe;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import javax.crypto.Cipher;
    import java.io.ByteArrayOutputStream;
    import java.security.KeyFactory;
    import java.security.Security;
    import java.security.Signature;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    @NotThreadSafe
    public class EccHelper {
        private static final Logger logger = LoggerFactory.getLogger(EccHelper.class);
        private static final int SIZE = 4096;
        private BCECPublicKey  publicKey;
        private BCECPrivateKey privateKey;
    
        static {
            Security.addProvider(new BouncyCastleProvider());
        }
    
        public EccHelper(String publicKey, String privateKey) {
            this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
        }
    
        public EccHelper(byte[] publicKey, byte[] privateKey) {
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
                if (publicKey != null && publicKey.length > 0) {
                    this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
                }
                if (privateKey != null && privateKey.length > 0) {
                    this.privateKey = (BCECPrivateKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
                }
            } catch (ClassCastException e) {
                throw new RuntimeException("", e);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public EccHelper(String publicKey) {
            this(Base64Util.decode(publicKey));
        }
    
        public EccHelper(byte[] publicKey) {
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
                if (publicKey != null && publicKey.length > 0) {
                    this.publicKey = (BCECPublicKey)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.");
            }
            try {
                Cipher cipher = Cipher.getInstance("ECIES", "BC");
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                int size = SIZE;
                ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 45));
                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.");
            }
            try {
                Cipher cipher = Cipher.getInstance("ECIES", "BC");
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                int size = SIZE + 45;
                ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size + 44) / (size + 45) * 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("ecc decrypt failed.", e);
            }
            return null;
        }
    
        public byte[] sign(byte[] content) {
            if (privateKey == null) {
                throw new RuntimeException("private key is null.");
            }
            try {
                Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
                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.");
            }
            try {
                Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
                signature.initVerify(publicKey);
                signature.update(content);
                return signature.verify(sign);
            } catch (Exception e) {
                logger.error("ecc verify failed.", e);
            }
            return false;
        }
    }

    5. 各种加密算法对比

    5.1. 散列算法比较

    名称 安全性 速度
    SHA-1
    MD5

    5.2. 对称加密算法比较

    名称 密钥名称 运行速度 安全性 资源消耗
    DES 56位 较快
    3DES 112位或168位
    AES 128、192、256位

    5.3. 非对称加密算法比较

    名称 成熟度 安全性 运算速度 资源消耗
    RSA 高
    ECC

    5.4. 对称算法与非对称加密算法

    5.4.1. 对称算法

    1. 密钥管理:比较难,不适合互联网,一般用于内部系统

    2. 安全性:中

    3. 加密速度:快好 几个数量级 (软件加解密速度至少快 100 倍,每秒可以加解密数 M 比特 数据),适合大数据量的加解密处理

    5.4.2. 非对称算法

    1. 密钥管理:密钥容易管理

    2. 安全性:高

    3. 加密速度:比较慢,适合 小数据量 加解密或数据签名

    小结

    本文介绍了 数字签名加密和解密对称加密和非对称加密,然后详细介绍了 MD5SHA-1HMACDES/AESRSAECC 这几种加密算法和代码示例。


    欢迎关注技术公众号: 零壹技术栈

    零壹技术栈

    本帐号将持续分享后端技术干货,包括虚拟机基础,多线程编程,高性能框架,异步、缓存和消息中间件,分布式和微服务,架构学习和进阶等学习资料和文章。

    展开全文
  • 加密算法总结

    万次阅读 2016-07-28 16:51:42
    加密算法总结, 对称加密,非对称加密,单向加密, MD5, MD5、SHA、HMAC、RIPE-MD、HAVAL、N-Hash、Tiger、DES、AES、IDEA、BlowFish、Twofish、RSA、DSA、ECC

    一、单向散列算法

    也称为Hash(哈希)算法。是一种将任意长度的消息压缩到某一固定长度(消息摘要)的函数(该过程不可逆)。Hash函数可用于数字签名、消息的完整性检测、消息起源的认证检测等。常见的散列算法有MD5SHAHMACRIPE-MDHAVALN-HashTiger等。

    1. MD5算法

    MD5消息摘要算法(Message Digest Algorithm 5)。
    MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
    MD5编码是最常用的编码方法之一,是从一段字符串中通过相应特征生成一段32位的数字字母混合码。

    MD5主要特点是 不可逆,相同数据的MD5值肯定一样,不同数据的MD5值不一样(也不是绝对的,但基本是不能一样的)。
    MD5算法还具有以下性质:
    1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
    2、容易计算:从原数据计算出MD5值很容易。
    3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
    4、弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
    5、强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。

    MD5虽然说是不可逆的 但是由于有网站http://www.cmd5.com的存在,专门用来查询MD5码 所以有的简单的MD5码是可以在这里搜到源码的。
    为了让MD5码更加安全 涌现了很多其他方法 如加盐。 盐要足够长足够乱 得到的MD5码就很难查到。

    2. SHA算法

    安全散列算法(Secure Hash Algorithm)简称SHA。有SHA-1SHA-256SHA-384SHA-512几种,分别产生160位、256位、384位和512位的散列值。

    2.1 SHA-1算法

    是一种主流的散列加密算法,设计时基于和MD4相同的原理,并模仿了该算法。消息分组和填充方式与MD5相同。也用到了一些常量做初始化数据。
    总结,随着密码分析技术的发展,现有的散列算法都是不安全的。如SHA-160MD5RIPEMDHAVALTiger在某些条件下能构造出碰撞。建议选择SHA-256/384/512,或者Whirlpool。如果在解密时碰到Hash算法,一般只需根据每种Hash算法的特征搞清楚具体哪一种Hash算法以及是否为某种算法的变形,继而通过该Hash的源代码即可破解。

    名称 安全性 运算速度
    SHA-1 慢(消息验证)
    MD5 快(消息验证)

    3.HMAC

    HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。

    二、对称加密算法

    加密密钥和解密密钥是完全相同的。其安全性依赖于:
    1.加密算法足够强。
    2.密钥的秘密性。

    常见的对称分组加密算法有DES(Data Encryption Standard)、AES(Advanced Encryption Standard)、IDEA(International Data Encryption Algorithm)、BlowFishTwofish等。

    这里写图片描述

    1. DES算法

    DES(Data Encryption Standard)是一种单一密钥对称加解密算法。通信主体之间只有一个密钥,该密钥不对第三方公开。但由于密钥长度较短,导致安全性不高。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密,如果Mode为加密,则用Key去把数据Data进行加密,生成Data的密码形式作为DES的输出结果;如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式作为DES的输出结果。在使用DES 时,双方预先约定使用的”密码”即Key,然后用Key去加密数据;接收方得到密文后使用同样的Key解密得到原数据,这样便实现了安全性较高的数据传输。

    2. 3DES算法

    三重DES(TDEA,Triple Data Encryption Algorithm)算法,这种方法用两个密钥对明文进行三次加密,假设两个密钥是K1和K2,三个步骤:1. 用密钥K1进行DEA加密。 2. 用K2对步骤1的结果进行DES解密。 3. 用步骤2的结果使用密钥K1进行DES加密。这种方法的缺点,是要花费原来三倍时间,从另一方面来看,三重DES的112位密钥长度是很“强壮”的加密方式了。

    3. AES算法

    AES(Advanced Encryption Standard,高级加密标准),用于替代DES成为新一代的加密标准。具有128比特的分组长度,并支持128、192和256比特的密钥长度,可在全世界范围内免费得到。其前身为Rijndael(读作:Rain Doll)。Rijndael算法与AES的唯一区别在于各自所支持的分组长度和密码密钥长度的反胃不同。Rijndael是具有可变分组长度和可变密钥长度的分组密码,其分组长度和密钥长度均可独立地设定为32比特的任意倍数,最小值128bit,最大256bit。而AES将分组长度固定为128位,而且仅支持128、192和256位的密钥长度,分别称为AES-128AES-192AES-256

    4. RC4流密码

    现今最为流行的流密码,应用于SSL(Secure Sockes Layer)、WEPRC4生成一种称为密钥流的伪随机流,它同明文通过异或操作相混合以达到加密的目的。解密时,同密文进行异或操作。其密钥流的生成有两部分组成:KSA(the Key-Scheduling Algorithm)和PRGA(the Pseudo-Random Generation Algorithm)。由于RC4算法加密采用XOR,所以一旦密钥序列出现重复,密文就有可能被破解。推荐使用RC4算法时,必须对加密密钥进行测试,判断其是否为弱密钥。

    5. TEA算法

    TEA(Tiny Encryption Algorithm)算法。分组长度为64位,密钥长度为128位。采用Feistel网络。其作者推荐使用32次循环加密,即64轮。TEA算法简单易懂,容易实现。但存在很大的缺陷,如相关密钥攻击。由此提出一些改进算法,如XTEA

    6. IDEA算法

    IDEA(International Data Encryption Algorithm)国际数据加密算法。分组密码IDEA明文和密文的分组长度为64位,密钥长度为128位。该算法的特点是使用了3种不同的代数群上的操作。IDEA共使用52个16位的子密钥,由输入的128位密钥生成。加密过程由8个相同的加密步骤(加密轮函数)和一个输出变换组成。而解密过程与加密过程相同。解密与加密唯一不同的地方就是使用不同的子密钥。首先,解密所用的52个子密钥是加密的子密钥的相应于不同操作运算的逆元,其次,解密时子密钥必须以相反的顺序使用。

    7. BlowFish算法

    BlowFish算法是一个64位分组及可变密钥长度的分组密码算法,该算法是非专利的。BlowFish算法基于Feistel网络(替换/置换网络的典型代表),加密函数迭代执行16轮。分组长度为64位(bit),密钥长度可以从32位到448位。算法由两部分组成:密钥扩展部分和数据加密部分。密钥扩展部分将最长为448位的密钥转化为共4168字节长度的子密钥数组。其中,数据加密由一个16轮的Feistel网络完成。每一轮由一个密钥相关置换和一个密钥与数据相关的替换组成。

    对称加密对比

    名称 密钥长度 运算速度 安全性 资源消耗
    DES 56位 较快
    3DES 112位或168位
    AES 128、192、256位

    三、非对称加密算法

    又称为公开密钥加密算法(Asymmetric Key Cryptography),需要两个密钥:公开密钥(public key)和私有密钥(private key)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。

    这里写图片描述

    1. RSA算法

    RSA(算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman), 是第一个既能用于数据加密也能用于数字签名的算法,易于理解和操作,应用广泛。RSA的安全性依赖于大整数因子分解。目前来看,攻击RSA算法最有效的方法便是分解模n。一般认为RSA需要1024位或更长的魔术才有安全保障。

    2. DSA数字签名算法

    DSA(Digital Signature Algorithm), 是在借鉴了ElGamal及Schnorr签名算法的基础上,公布的数字签名标准(Digital Signature Standard),该标准采用的算法。其安全性同样基于有限域的离散对数问题。目前DSA的应用越来越广泛。

    3. ECC椭圆曲线密码编码学

    相比RSA等公钥算法,使用较短的密钥长度而能得到相同程度的安全性。预测未来ECC(Elliptic Curve Cryptography)将会取代RSA成为主流的密钥算法。

    4. ElGamal公钥算法

    其完全依赖于在有限域上计算离散对数的困难性。ElGamal的一个不足之处是密文的长度是明文的两倍。而另一种签名算法,Schnorr签名系统的密文比较短,这是由其系统内的单向散列函数决定的。

    私钥加密、公钥解密——签名

    非对称算法的私钥加密、公钥解密会被用于数字签名,一般用于防篡改和伪装。发送方拥有私钥,接收方拥有公钥。一般流程如下:
    1.发送方选择一种算法(最常用的算法是MD5),对原始数据进行计算生成摘要
    2.发送方算出摘要后,用私钥对其进行加密,得到的结果称为原始数据的签名。然后把原始数据和签名一起发送给接收方。
    3.接收方收到发来的数据后,通过公钥对收到的签名进行解密,最后获得发送方的摘要
    4.接收方用与发送方计算摘要一致的算法对收到的原始数据进行计算,得到由原始数据计算得到的本地摘要
    5.接收方将本地计算的摘要和发送方的摘要进行对比。若结果一致,则证明没有被篡改过。

    watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9kY3NuYWlsLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70

    在这个过程中,就是一个私钥加密,公钥解密的过程,用于验证数据完整性和发送方身份的。而公钥加密,私钥解密,是用于防止数据被第三方得到。当然,签名的效率要比非对称加密的效率要高的多。

    非对称加密对比

    名称 成熟度 运算速度 安全性(取决于密钥长度) 资源消耗
    RSA
    DSA 只能用于数字签名
    ECC 低(计算量小,存储空间小,带宽要求低)

    四、对称与非对称算法比较

    名称 运算速度 密钥管理 安全性
    对称算法 比较难,不适合互联网,一版用于内部系统 快好几个数量级,适合大数据量的加解密
    非对称算法 容易管理 慢,适合小数据量加解密或数据签名

    对称密码体制的特点

    优点:算法公开、计算量小、加密速度快、加密效率高、可逆
    缺点:双方使用相同钥匙,安全性得不到保证
    现状:对称加密的速度比公钥加密快很多,在很多场合都需要对称加密,
    相较于DES和3DES算法而言,AES算法有着更高的速度和资源使用效率,安全级别也较之更高了,被称为下一代加密标准

    非对称密码体制的特点

    优点: 非对称加密使用了一对密钥,公钥与私钥,所以安全性高。
    缺点:加解密速度慢的特点,密钥尺寸大。

    总结

    由于非对称加密算法的运行速度比对称加密算法的速度慢很多,当我们需要加密大量的数据时,建议采用对称加密算法,提高加解密速度。

    对称加密算法不能实现签名,因此签名只能非对称算法。

    由于对称加密算法的密钥管理是一个复杂的过程,密钥的管理直接决定着他的安全性,因此当数据量很小时,我们可以考虑采用非对称加密算法。

    在实际的操作过程中,我们通常采用的方式是:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。RSA建议采用1024位的数字,ECC建议采用160位,AES采用128为即可。

    五、混合加密

    通信双方的通信过程分为两个部分,双方先利用非对称加密技术传送本次通信所用的对称密钥,然后再用对称加密技术加密传送文件。

    这里写图片描述

    六、其他算法

    1. Base64编码

    Base64编码是将二进制数据编码为可现实的字母和数字,用于传送图形、声音和传真等非文本数据。常用于MIME电子邮件格式中。其使用含有65个字符的ASCII字符集(第65个字符为“=”,用于对字符串的特殊处理过程),并用6个进制位表示一个可显示字符。

    把数据编码为Base64,将第一个字节放置于24位缓冲区的高8位,第二个字节放置于中间的8位,第三个字节放置于低8位。如果是少于3个字节的数据,相应的缓冲区置0。然后对24位缓冲区以6位为一组作为索引,高位优先,从字符串“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789+/”中取出相应的元素作为输出。如果仅有一个或两个字节输入,那么只使用输出的两个或三个字符,其余的用“=”填充。

    解码过程是编码的逆过程。首先得到Base64字符串的每个字符在Base64码表中的索引,然后将这些索引的二进制连接起来,重新以8位为一组进行分组,即可得到源码。

    1. Base24码表
      BCDFGHJKMPQRTVWXY2346789
    2. Base32码表:
      ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
    3. Base60码表:
      0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwx
      Windows产品序列号就是使用Base24编码。实际使用时,码表会和标准码表不一样,但原理相同。

    2. CRC32算法

    CRC(Cyclic Redundancy Checksum 或者 Cyclic Redundancy Check), 是对数据的校验值,中文为“循环冗余校验码”,常用语校验数据完整性。最常见的CRCCRC32,即数据校验值为32位。CRC32代码量小,容易理解,所以目前应用十分广泛。但同时CRC32并不是一个安全的加密算法。如果需要更安全的完整性校验算法,建议使用数字签名技术。

    七、常见的加密库

    1. Miracl大数运算库

    Miracl(Multiprecision Integer and Rational Arithmetic C/C++ Library),多精度整数和有理数算术运算C/C++库。它是一个大数库,实现了设计使用大数的加密技术的最基本的函数。支持RSA公钥系统、Diffie-Hellman密钥交换、DSA数字签名系统及基于GF(p)和GF(2m)的椭圆曲线加密系统。其提供了C和C++两种接口,使用方便,速度快,开源。

    2. FGInt

    FGInt(Fast Gigantic Integers),是用于Delphi的一种可以实现常见的公钥加密系统的库。

    3. freeLIP

    最初设计用于进行RSA-129挑战大数计算的大数库,采用2的30次方进制来表示大数,速度不及miracl

    4. Crypto++

    一个实现了相当数量的加密算法的加密库。使用了C++的高级语法,文档较少,不易上手。

    5. LibTomCrypt

    一款相当不错的加密算法库。包括了常见的散列算法、对称算法及公钥加密系统。接口友好,非常适合C程序员使用。

    6. GMP

    全称GNU Multiple Precision Arithmetic Library。其核心采用汇编实现,速度非常快,超过miracl,常用来实现大整数因子的分解。

    7. OpenSSL

    主要用于网络安全,也包含了一些加密算法的实现。如对称算法中的BlowFishIDEADESCAST,公钥中的RSADSA,散列中的MD5RIPEMDSHA等。

    8. DCP和DEC

    DCP全称Delphi Cryptography Package,DEC全称Delphi Encryption Compendium,都是用于Delphi的一种加密算法库。这两个算法库实现了大部分常见的散列算法及对称算法,使用方便。

    9. Microsoft Crypto API

    是微软为了方便程序员在软件中进行数字签名、数据加密的开发而提供的一套加密系统。接口友好方便。

    10. NTL

    是一个可以用于数论相关计算的库。提供了非常友好的C++接口,用于实现有符号的、算术整数的运算,以及向量、矩阵、基于有限域和整数的多项式运算。在密码学中,有限域的应用相当广泛,如AEStwofishECC等都涉及有限域。

    加密应用

    1. 通过简单的URLENCODEBase64编码防止数据明文传输。
    2. 对普通请求、返回数据,生成MD5校验(MD5中加入动态密钥),进行数据完整性(简单防篡改,安全性较低,优点:快速)校验。
    3. 对于重要数据,使用RSA进行数字签名,起到防篡改作用。
    4. 对于比较敏感的数据,如用户信息(登陆、注册等),客户端发送使用RSA加密,服务器返回使用DES(AES)加密。原因是, 客户端发送之所以使用RSA加密,是因为RSA解密需要知道服务器私钥,而服务器私钥一般盗取难度较大;如果使用DES的话,可以通过破解客户端获取密钥,安全性较低。而服务器返回之所以使用DES,是因为不管使用DES还是RSA,密钥(或私钥)都存储在客户端,都存在被破解的风险,因此,需要采用动态密钥,而RSA的密钥生成比较复杂,不太适合动态密钥,并且RSA速度相对较慢,所以选用DES

    用户登录注册加密机制

    1.客户端注册过程

    客户端注册账号时,需要先将账号发送给服务器,向服务器申请一个只属于当前用户的密钥。客户端需要把该密钥保存到本地,直接作为后面HMAC的密钥。

    然后,客户端将用户的密码进行MD5加密,再使用刚刚保存的密钥进行HMAC加密。最后将账号和密码发送给服务器,服务器端就注册成功了。服务器端会保留用户的账号密码的MD5账号密钥的数据。而且在不修改密码和更换客户端的情况下,账号密钥密码的MD5只会传输一次,所以这也降低了许多风险。

    2.客户端登录过程

    客户端登录时,需要再次对密码进行MD5加密,并使用保存的密钥进行HMAC加密。然后发送给服务器,服务器会拿出当前用户注册时留下的密码的MD5通过密钥进行HMAC加密,作对比。如果比对结果一致,就成功登录了。

    3.更换客户端登录

    如果用户在另一台客户端进行登录,就需要重新申请一次密钥。因为本地的密钥要么为空,要么与当前用户的账号不对应。服务器返回密钥后,并保存到本地,然后重新开始登录流程。

    4.数据传输安全

    当然,这只是原理性的讨论,在实际中要复杂许多。虽然服务器不会明文保存密码,但并不能说明这些密码的MD5是安全的。市面上有许多MD5的对比库,一旦泄露也很危险。所以,我们还需要在MD5前对密码进行加盐处理。

    另外,还要对请求增加时间戳校验,不给居心不良的人留下足够时间。还要增加完整性校验,防止请求被篡改。这些都是数据传输安全处理的事务了,因为你的登录注册也是基于你的网络请求的,需要由数据传输安全来保障你的网络层业务。

    参考资料:
    单向加密算法MD5和SHA
    对称加密算法DES、3DES和AES
    算法

    展开全文
  • 加密算法介绍及加密算法的选择

    万次阅读 2015-09-22 13:57:46
    加密算法介绍 一. 密码学简介 据记载,公元前400年,古希腊人发明了置换密码。1881年世界上的第一个电话保密专利出现。在第二次世界大战期间,德国军方启用“恩尼格玛”密码机,密码学在战争中起着非常重要的...
  • 几种常用的密码加密算法以及选用

    万次阅读 2018-05-07 10:40:52
    原链接:http://www.cnblogs.com/yangywyangyw/archive/2012/07/31/2620861.html加 密算法通常分为对称性加密算法和非对称性加密算法,对于对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同...
  • 十分钟读懂AES加密算法

    万次阅读 多人点赞 2017-09-23 10:07:28
    今天看了Moserware的《A Stick Figure Guide to the Advanced Encryption Standard(AES)》收获了不少,对AES算法有了更加清楚的理解,这篇博客用了大量的情景图文来展示AES的发展历史和算法的具体流程,虽然是2009年...
  • 加密算法------DES加密算法详解

    万次阅读 多人点赞 2018-04-13 21:15:59
    一、加密算法的分类1.对称加解密算法a.通信双方同时掌握一个密钥,加密解密都是由一个密钥完成的(即加密密钥等于解密密钥,加解密密钥可以相互推倒出来)。b.双方通信前共同拟定一个密钥,不对第三方公开。c.不具有...
  • 目前常见加密算法简介

    千次阅读 2019-01-13 15:15:35
    艾伦·麦席森·图灵在二战期间主要负责破译德国人的密码系统... 后来甚至有人将二战胜利原因归咎于图灵机的诞生,虽然有些夸大,但图灵机的诞生确实加快了二战的结束这是不可否认的。而图灵机战胜的不是法西斯...
  • 常见加密算法及常见加密算法原理

    万次阅读 2018-08-09 17:16:11
    加密算法和协议 对称加密 简介:加密和解密使用同一个密钥 常见的算法: - DES:Data Encryption Standard; - 3DES:Triple DES; - AES:Advanced Encryption Standard; (128bits, 192bits, 256bits, 384...
  • AES 加密算法的原理详解

    万次阅读 多人点赞 2018-07-23 22:18:49
    高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图: 下面简单介绍下各个部分的....
  • 常用加密算法之非对称加密算法

    万次阅读 2018-03-16 21:44:45
    非对称加密算法 非对称加密算法是一种密钥的保密方法。非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有...
  • 加密算法简介

    千次阅读 2006-05-13 22:43:00
    随 着信息化和数字化社会的发展,人们对信息安全和保密的重要性认识不断提高,于是在1997年,美国国家保准局公布实施了“美国数据加密标准(DES)”, 民间力量开始全面介入密码学的研究和应用中,采用的加密算法有...
  • 椭圆曲线加密算法

    万次阅读 2018-02-01 16:02:23
    ECC被公认为在给定密钥长度下最安全的加密算法。比特币中的公私钥生成以及签名算法ECDSA都是基于ECC的。下面简单介绍ECC以及ECDSA的原理。 从公钥加密说起   公钥加密,也称非对称加密。可以说...
  • 在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。常用的对称加密算法:AES,RC4,3DES传输的示意图如下所示:如上图所示,此种...
  • 对称加密算法和非对称加密算法

    千次阅读 2017-06-16 18:47:36
    (一)对称加密(Symmetric Cryptography)对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key),这种方法在密码学中叫做对称加密算法。对称加密有很多...
  • 通信加密算法

    千次阅读 2018-03-10 23:39:41
    1. 加密算法分类加密算法通常分为对称性加密算法和非对称性加密算法。对于对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行加解密了。非对称算法与之不同,发送双方A...
  • 单向加密算法

    千次阅读 2016-03-30 14:51:00
    MD5,SHA算法是单向加密算法的代表,单向加密算法是数据完整性验证的常用算法。对称加密算法: DES算法是典型的对称加密算法的代表,对称加密算法是数据存储加密的常用算法非对称算法: RSA算法是典型的非对称
  • 国密加密算法与国际加密算法

    千次阅读 2019-05-17 10:59:09
    国密算法: ...采用该算法已经研制了系列芯片、智能IC卡、智能密码钥匙、加密卡、加密机等安全产品,广泛应用于电子政务、电子商务及国民经济的各个应用领域(包括国家政务通、警务通等重要领域)。 ...
  • RSA加密算法

    万次阅读 多人点赞 2018-04-17 09:38:31
    公开密钥加密公开密钥加密(public-key cryptography),也成为非对称加密,是密码学的一种算法,他需要两个密钥,一个是公开密钥,另一个是私有密钥,一个用作加密的时候,另一个则用作解密。明文:需要加密的内容,...
1 2 3 4 5 ... 20
收藏数 273,690
精华内容 109,476
关键字:

加密算法