JAVA加密系列(三)- 非对称加密算法 RSA、DSA

JAVA加密系列(三)- 非对称加密算法 RSA、DSA

非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方;甲方再用自己私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。

算法介绍

常见算法

  • RSA 第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,截止2017年被普遍认为是最优秀的公钥方案之一。
  • DSA Elgamal和Schnorr数字签名的一个变种,DSA数字签名优于Elgamal数字签名的地方在于它的签名长度较短,并且某些可以破解Elgamal方案的攻击不适用DSA数字签名
  • ECC 椭圆曲线密码编码学,是目前已知的公钥体制中,对每比特所提供加密强度最高的一种体制。在软件注册保护方面起到很大的作用,一般的序列号通常由该算法产生。
  • Elgamal 其基础是DiffieˉHellman密钥交换算法,应对中间人攻击时非常脆弱。

RSA

X509EncodedKeySpec和PKCS8EncodedKeySpec分别对应值公钥和私钥的规范 想对算法编码和规范有更多了解的可以更深入的学习,以下例子只展示最简单的使用

public class RSAUtil {

    //必须16位  否则会报错  偏移量
    private static String IV = "asdfgh1234567890";
    //钥匙  必须16位
    private static String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCA6exxuVOdLvxb6u+Gf5FvZD6zGO1sqDbW7zBgga/8LVZBktaljn0OzCjQKbfe/AQgyh/nIVi1zFO1+FC9cGSiWPGo1uX9kY5Chm0MS8UhtNfO13sOD0U/47MMOduuQ3WP+EJ0wFRvpzyGAp0vKqfCj3Hyrtaf8o7CqTGoLV7G7QIDAQAB";
    private static String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIDp7HG5U50u/Fvq74Z/kW9kPrMY7WyoNtbvMGCBr/wtVkGS1qWOfQ7MKNApt978BCDKH+chWLXMU7X4UL1wZKJY8ajW5f2RjkKGbQxLxSG0187Xew4PRT/jsww5265DdY/4QnTAVG+nPIYCnS8qp8KPcfKu1p/yjsKpMagtXsbtAgMBAAECgYBXf+94BWWmg9TQgvdPYFkTtYQFRj8pCEgovTMl3gDYduFcItHEj6F8oMB3AkoGdSJMK0VaOT0gMG8FTWVoH9h9iSM5uu/wsqr7mFI13+18bGFNv0OotV4UNpvlXqSksoRmetZDtaDPhO9/6anD1zY8VrJMXzJfJXhNdGFArEjpwQJBAOBsvzNDy1w/QtLobDm+TSOVVNtoPMO5qddR5PRnRWtpKASY4dQDl/KPa1fDrNp3oGfqA5FPLrQCmd6502Mvmn0CQQCTDRgarAuH9UVgGDeR+E18lWBsZEM4mGHFi9aigeLEw0th8PqZpdrPJixSo4S2lKcopkkagljiYONLlVeznBkxAkEAvRvloZUm73x/GqmvSJkK90kGUDvtuB/i9gWUID5FSNU7W2RYJwdAKqyfjzzbktvq1qVijDdk61qlvgBoF9QtIQJAcIammVJqCIHxspUVgQfHE7yi6o7Wuaoxtx9JAVXvF65yMuJagdTe2YFWjW4/kg+y0nJcooJ4TdLiW+ZOFE0xIQJBAILYIuxY5OpAm8cMqLOtldczj4sFfZb7hhojcEm3+/0ezNhzhZWPMI6txFieDel40a/qdPr8EPZjc0uYKTtlKNc=";

    public static void main(String[] args) {
//        genKeyPair();
        //字符串编码
        System.out.println("编码结果:" + encrypt("hello world", PUBLIC_KEY));
        //字符串解码
        System.out.println("编码结果:" + decrypt("NEo+98UAvp0q69M1mxorD/zrL4QjhBGAFd2Wj2nGcsF8Txb9r8VnUvFqGUM7ZNwXZdcnzW/SZqbGc8rHT0mmtPGWMlzJV8jMAWUgOh9jozyablwWU8Uj4BItiderZSQTrD+3E+ZL5TkkQKwmNCmdaABmozpkUz4B893m3GzhpjQ=",PRIVATE_KEY));
    }

    /**
     * 随机生成密钥对
     */
    public static void genKeyPair() {
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 初始化密钥对生成器,密钥大小为96-1024位
            keyPairGen.initialize(1024);
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 得到公钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            // 得到公钥字符串
            String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
            // 得到私钥字符串
            String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
            // 打印公钥和私钥
            System.out.println("公匙:" + publicKeyString);
            System.out.println("私匙:" + privateKeyString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 加密
     */
    public static String encrypt(String str, String publicKey) {
        try {
            byte[] bytes = str.getBytes();
            //获得RSA公匙
            RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey.getBytes())));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
            bytes = cipher.doFinal(bytes);
            return new String(Base64.getEncoder().encode(bytes));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 解密
     */
    public static String decrypt(String str, String privateKey) {
        try {
            byte[] bytes = Base64.getDecoder().decode(str);
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey.getBytes())));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
            bytes = cipher.doFinal(bytes);
            return new String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
log
编码结果:eZxSLJKOvj0Ee/Lg9cx61ppaKuWXSRxvDU1deLR0ll2x1GEW5WO8Q9B4rO4DxDWfCLqfdmunSs2YZkm8ZDBUYi0N6VV4mqoz2SjckJyVe3pjwh4DifdrjAoO+0aYPKMhlGLjMY4Iy5SmkuSmot2AjsKHBhoqGs8bPnZoT7S6iKY=
编码结果:hello word

DSA

Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。简单的说,这是一种更高级的验证方式,用作数字签名。不单单只有公钥、私钥,还有数字签名。私钥加密生成数字签名,公钥验证数据及签名。如果数据和签名不匹配则认为验证失败!也就是说传输中的数据可以不再加密,接收方获得数据后,拿到公钥与签名比对数据是否有效!

public class DSAUtil {

    private static String PUBLIC_KEY = "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAMUKDkoben3PPK01uS7hXrxKSOgJpQxVigU7mkfQL87B5GtwUKWmdKM5nMC89avU/S3qTg95+dQKjgydYqe8Ej3SVzDwnGlkZzWGgUOgs0pQ8q/cJ++4eUETH3l4svsLzwDgKIoT3fDBUef3fZ95oWbe1pIIt8RN0KRFJw8U+r4A";
    private static String PRIVATE_KEY = "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUa38CMSvzE1kkWgLiBQDrKCavBEk=";

    public static void main(String[] args) {
        //随机生成成对密钥
        genKeyPair();

        String sign=sign("hello world", PRIVATE_KEY);

        System.out.println("数字签名:" + sign);
        //字符串解码
        System.out.println("数字签名校验:" + verify("hello word",sign,PUBLIC_KEY));
    }

    /**
     * 随机生成密钥对
     */
    public static void genKeyPair() {
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于DSA算法生成对象 可以使用RSA算法生成 成对出现就好
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA");
            // 初始化密钥对生成器,密钥大小为96-1024位 可自定义随机产生器 SecureRandom
            keyPairGen.initialize(1024);
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私钥
            DSAPrivateKey privateKey = (DSAPrivateKey) keyPair.getPrivate();
            // 得到公钥
            DSAPublicKey publicKey = (DSAPublicKey) keyPair.getPublic();
            // 得到公钥字符串
            String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
            // 得到私钥字符串
            String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
            // 打印公钥和私钥
            System.out.println("公匙:" + publicKeyString);
            System.out.println("私匙:" + privateKeyString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 用私钥对信息生成数字签名
     */
    public static String sign(String str, String privateKey) {
        try {
            byte[] bytes = str.getBytes();
            //获得DSA公匙
            DSAPrivateKey keyFactory = (DSAPrivateKey) KeyFactory.getInstance("DSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey.getBytes())));
            Signature signature=Signature.getInstance("DSA");
            signature.initSign(keyFactory);
            signature.update(bytes);
            return new String(Base64.getEncoder().encode(signature.sign()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 校验数字签名
     */
    public static boolean verify(String str, String sign,String publicKey) {
        try {
            byte[] bytes =Base64.getDecoder().decode(sign);
            DSAPublicKey keyFactory = (DSAPublicKey) KeyFactory.getInstance("DSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey.getBytes())));
            Signature signature=Signature.getInstance("DSA");
            signature.initVerify(keyFactory);
            signature.update(str.getBytes());
            return signature.verify(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}
log
公匙:MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGANQY1Hf9XoQcFocGugqaEP6xPgxPsZ1C63Zs1WWg4Fk6CV8xuK78hgk+BhVit2/h97DWp7LyTDT4gVjCHLuV58TUmZyiupeo0FZrKqrAr+t3Der9+MmBDzfvkgPPIIZudhoqJcTpox8UNdJ4yyvgXxMN4DSoWJ4O28q0jBaxC/Mk=
私匙:MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUcsPeT/5R1AiwvTpJmzv5TQxq65Q=
数字签名:MCwCFGB6J9g/R5su1o3TbZYMAcroY6YIAhQTtbtXUH47pGRDzMCu74eq0sOMCg==
数字签名校验:true

总结

非对称性加密还有很多,RSA和DSA是比较常用和常见的加密方式,安全性来讲两者差不多,DSA只是一种算法,和RSA不同之处在于它不能用作加密和解密,也不能进行密钥交换,只用于签名,它比RSA要快很多,RSA啥都好,但是RSA算法的秘钥很长,加密的计算量比较大,安全性较高,但是加密速度比较慢,所以RSA加密常用于少量的核心数据的加密。

源码下载

GitHub,感兴趣的点个星星

详情文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271