加密算法

加密算法分类

  • 单向加密,不可逆,即加密后无法解密,只能通过判断加密后的信息是否一致判断是否是同一个输入(有重复的可能),主要有MD5和SHA
  • 对称加密,可逆,加密和解密使用相同的密钥,可以通过秘文解析出明文,主要有DES,3DES和AES
  • 非对称加密,加密和解密使用不同的密钥,公开密钥(publickey)和私有密钥(privatekey),如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密,主要有RSA

单向加密

MD5

对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。然后,在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,信息的位长=N512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。

所以,MD5的性能和加密的数据量成反比,不过MD5的性能也是很高的,毫秒级别

public static void main(String[] args) throws Exception {
        String inStr = "md5 input content";
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
            System.out.println("");
        }
        byte[] byteArray = inStr.getBytes("UTF-8");
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        System.out.println("input:" + inStr);
        System.out.println("md5 output:" + hexValue.toString());
    }

SHA加密

SHA接收一段明文,然后以一种不可逆 的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也 称为信息摘要或信息认证代码)的过程。散列函数值可以说是对明文的一种“指纹”或是“摘要”所以对散列值的数字签名就可以视为对此明文的数字签名


    public static void main(String[] args) throws Exception {
        String inStr = "sha input";
        MessageDigest sha = null;
        try {
            sha = MessageDigest.getInstance("SHA");
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
            System.out.println("");
        }
        byte[] byteArray = inStr.getBytes("UTF-8");
        long time = System.currentTimeMillis();
        byte[] shaBytes = sha.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < shaBytes.length; i++) {
            int val = ((int) shaBytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        System.out.println("use time:" + (System.currentTimeMillis()  -time));
        System.out.println("input:" + inStr);
        System.out.println("sha output:" + hexValue.toString());
    }

SHA的API和MD5类似,只是修改了获取算法的参数

MD5和SHA的对比

  • 由于SHA的摘要长度要比MD5长32位,所以会更安全些
  • MD5的速度要比SHA的速度快些

对称加密

对称加密的算法的入口参数(非JavaAPI)有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密
对称加密算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位

对称加密有5种模式
1)ECB:电子密码本(不推荐使用,每次加密均产生独立的密文分组,并且对其他的密文分组不会产生影响,也就是相同的明文加密后产生相同的密文)
2)CBC:密文链接(常用的,推荐使用,明文加密前需要先和前面的密文进行异或运算,也就是相同的明文加密后产生不同的密文)
除了这两种常用的工作模式,还有:
3)CFB:密文反馈
4)OFB:输出反馈
5)CTR:计数器

ECB模式

image.png

优点:

  • 简单;
  • 有利于并行计算;
  • 误差不会被传送;

缺点:

  • 不能隐藏明文的模式;
  • 可能对明文进行主动攻击。

CBC模式

image.png

优点:

  • 不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。

缺点:

  • 不利于并行计算;
  • 误差传递;
  • 需要初始化向量IV

分组密码填充方式

1)NoPadding:无填充
2)PKCS5Padding
3)ISO10126Padding

常用对称密码

1)DES(Data Encryption Standard,数据加密标准)
2)3DES(Triple DES、DESede,进行了三重DES加密的算法)
3)AES(Advanced Encryption Standard,高级数据加密标准,AES算法可以有效抵制针对DES的攻击算法)

image.png

以AES为例说明JavaAPI的使用,AES可以替换成:DESede(3DES加密),DES(DES加密),AES/CBC/PKCS5Padding(AES加密CBC模式PKCS5Padding填充方式,还可以改成其他组合,CBC模式需要传IV)

1)生成密钥
KeyGenerator keyGen = KeyGenerator.getInstance("AES");//密钥生成器
keygen.init(128);  //默认128,获得无政策权限后可为192或256
SecretKey secretKey = keyGen.generateKey();//生成密钥
byte[] key = secretKey.getEncoded();//密钥字节数组
2)AES加密
SecretKey secretKey = new SecretKeySpec(key, "AES");//恢复密钥
Cipher cipher = Cipher.getInstance("AES");//Cipher完成加密或解密工作类
cipher.init(Cipher.ENCRYPT_MODE, secretKey);//对Cipher初始化,解密模式
byte[] cipherByte = cipher.doFinal(data);//加密data
3)AES解密
SecretKey secretKey = new SecretKeySpec(key, "AES");//恢复密钥
Cipher cipher = Cipher.getInstance("AES");//Cipher完成加密或解密工作类
cipher.init(Cipher.DECRYPT_MODE, secretKey);//对Cipher初始化,解密模式
byte[] cipherByte = cipher.doFinal(data);//解密data

传IV的JavaAPI

public static void main(String[] args) {
        try {
            byte[] ivBytes = "HAHAABCFVCSDGKIO".getBytes();
            // 生成iv
            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
            //必须为16个字节
            byte[] keyBytes = "seedseedseedseed".getBytes();
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
            //推荐CBC模式模式
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] encrypted = cipher.doFinal("origin content".getBytes());
            System.out.println(Base64.encodeBase64String(encrypted));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

非对称加密

RSA

RSA作为常用的非对称加密算法,用法基本就是首先生成公钥和私钥密钥对,然后用公钥加密 私钥解密或者用私钥加密 公钥解密。

public class RSA {
    //非对称密钥算法
    private static final String KEY_ALGORITHM = "RSA";
    //密钥长度,在512到65536位之间,建议不要太长,否则速度很慢,生成的加密数据很长
    private static final int KEY_SIZE = 512;
    //字符编码
    private static final String CHARSET = "UTF-8";
 
    /**
     * 生成密钥对
     *
     * @return KeyPair 密钥对
     */
    public static KeyPair getKeyPair() throws Exception {
        return getKeyPair(null);
    }
 
    /**
     * 生成密钥对
     * @param password 生成密钥对的密码
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair(String password) throws Exception {
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥生成器
        if(password == null){
            keyPairGenerator.initialize(KEY_SIZE);
        }else {
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(password.getBytes(CHARSET));
            keyPairGenerator.initialize(KEY_SIZE, secureRandom);
        }
        //生成密钥对
        return keyPairGenerator.generateKeyPair();
    }
 
    /**
     * 取得私钥
     *
     * @param keyPair 密钥对
     * @return byte[] 私钥
     */
    public static byte[] getPrivateKeyBytes(KeyPair keyPair) {
        return keyPair.getPrivate().getEncoded();
    }
 
    /**
     * 取得Base64编码的私钥
     *
     * @param keyPair 密钥对
     * @return String Base64编码的私钥
     */
    public static String getPrivateKey(KeyPair keyPair) {
        return Base64.getEncoder().encodeToString(getPrivateKeyBytes(keyPair));
    }
 
    /**
     * 取得公钥
     *
     * @param keyPair 密钥对
     * @return byte[] 公钥
     */
    public static byte[] getPublicKeyBytes(KeyPair keyPair) {
        return keyPair.getPublic().getEncoded();
    }
 
    /**
     * 取得Base64编码的公钥
     *
     * @param keyPair 密钥对
     * @return String Base64编码的公钥
     */
    public static String getPublicKey(KeyPair keyPair) {
        return Base64.getEncoder().encodeToString(getPublicKeyBytes(keyPair));
    }
 
    /**
     * 私钥加密
     *
     * @param data       待加密数据
     * @param privateKey 私钥字节数组
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
        //数据加密
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }
 
    /**
     * 私钥加密
     *
     * @param data       待加密数据
     * @param privateKey Base64编码的私钥
     * @return String Base64编码的加密数据
     */
    public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
        byte[] key = Base64.getDecoder().decode(privateKey);
        return Base64.getEncoder().encodeToString(encryptByPrivateKey(data.getBytes(CHARSET), key));
    }
 
    /**
     * 公钥加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥字节数组
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成公钥
        PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
        //数据加密
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }
 
    /**
     * 公钥加密
     *
     * @param data      待加密数据
     * @param publicKey Base64编码的公钥
     * @return String Base64编码的加密数据
     */
    public static String encryptByPublicKey(String data, String publicKey) throws Exception {
        byte[] key = Base64.getDecoder().decode(publicKey);
        return Base64.getEncoder().encodeToString(encryptByPublicKey(data.getBytes(CHARSET), key));
    }
 
    /**
     * 私钥解密
     *
     * @param data       待解密数据
     * @param privateKey 私钥字节数组
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
        //数据解密
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(data);
    }
 
    /**
     * 私钥解密
     *
     * @param data       Base64编码的待解密数据
     * @param privateKey Base64编码的私钥
     * @return String 解密数据
     */
    public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
        byte[] key = Base64.getDecoder().decode(privateKey);
        return new String(decryptByPrivateKey(Base64.getDecoder().decode(data), key), CHARSET);
    }
 
    /**
     * 公钥解密
     *
     * @param data      待解密数据
     * @param publicKey 公钥字节数组
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //产生公钥
        PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
        //数据解密
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(data);
    }
 
    /**
     * 公钥解密
     *
     * @param data      Base64编码的待解密数据
     * @param publicKey Base64编码的公钥
     * @return String 解密数据
     */
    public static String decryptByPublicKey(String data, String publicKey) throws Exception {
        byte[] key = Base64.getDecoder().decode(publicKey);
        return new String(decryptByPublicKey(Base64.getDecoder().decode(data), key), CHARSET);
    }
 
    /**
     * 测试加解密方法
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //生成密钥对,一般生成之后可以放到配置文件中
        KeyPair keyPair = RSA.getKeyPair();
        //公钥
        String publicKey = RSA.getPublicKey(keyPair);
        //私钥
        String privateKey = RSA.getPrivateKey(keyPair);
 
        System.out.println("公钥:\n" + publicKey);
        System.out.println("私钥:\n" + privateKey);
 
        String data = "RSA 加解密测试!";
        {
            System.out.println("\n===========私钥加密,公钥解密==============");
            String s1 = RSA.encryptByPrivateKey(data, privateKey);
            System.out.println("加密后的数据:" + s1);
            String s2 = RSA.decryptByPublicKey(s1, publicKey);
            System.out.println("解密后的数据:" + s2 + "\n\n");
        }
 
        {
            System.out.println("\n===========公钥加密,私钥解密==============");
            String s1 = RSA.encryptByPublicKey(data, publicKey);
            System.out.println("加密后的数据:" + s1);
            String s2 = RSA.decryptByPrivateKey(s1, privateKey);
            System.out.println("解密后的数据:" + s2 + "\n\n");
        }
 
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容

  • 1. 介绍 数字签名、信息加密 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、oau...
    luckyYU阅读 10,577评论 1 6
  • 这篇文章主要讲述在Mobile BI(移动商务智能)开发过程中,在网络通信、数据存储、登录验证这几个方面涉及的加密...
    雨_树阅读 2,335评论 0 6
  • 对称与非对称加密算法的区别。 对称加密算法 加密(encryption)与解密(decryption)用的是同样的...
    步二小哥阅读 1,200评论 0 1
  • 在介绍加密算法之前, 先介绍一下 base64: 0. base64 Base64要求把每三个8Bit的字节转换为...
    reboot_q阅读 12,692评论 3 8
  • 概述 之前一直对加密相关的算法知之甚少,只知道类似DES、RSA等加密算法能对数据传输进行加密,且各种加密算法各有...
    Henryzhu阅读 3,008评论 0 14