Android 数据加密-RSA

RSA加密算法

1.RSA算法史:

RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)三位数学家提出。在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
但实际上,在1973年,在英国政府通讯总部工作的数学家克利福德·柯克斯(Clifford Cocks)在一个内部文件中提出了一个相同的算法,但他的发现被列入机密,一直到1997年才被发表。

2.RSA加密简介:

RSA加密是一种非对称加密。可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)

3.RSA加密、签名区别:

加密和签名都是为了安全性考虑,但略有不同。常有人问加密和签名是用私钥还是公钥?其实都是对加密和签名的作用有所混淆。简单的说,加密是为了防止信息被泄露,而签名是为了防止信息被篡改。这里举2个例子说明。

4.使用场景

场景一:

第一个场景:战场上,B要给A传递一条消息,内容为某一指令。
RSA的加密过程如下:
@1A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
@2A传递自己的公钥给B,B用A的公钥对消息进行加密。
@3A接收到B加密的消息,利用A自己的私钥对消息进行解密。
  在这个过程中,只有2次传递过程,第一次是A传递公钥给B,第二次是B传递加密消息给A,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行解密,防止了消息内容的泄露。

场景二:

第二个场景:A收到B发的消息后,需要进行回复“收到”。
RSA签名的过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
(2)A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
(3)B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。
  在这个过程中,只有2次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。

项目案例:

第二个场景:A收到B发的消息后,需要进行回复“收到”。
RSA签名的过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
(2)A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
(3)B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。
  在这个过程中,只有2次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。

5.RSA项目中加密流程

RSA是一种常用的非对称加密算法,所谓非对称加密是指使用一对密钥(公钥和私钥)进行加密和解密,公钥人人都可以获得,用于加密数据,私钥保存在服务器中,用于解密数据。加密解密过程如下:


RSA加密流程.png

使用RSA进行加密解密,其优点是非常不容易破解,缺点是和对称加密(如AES)相比,加密速度较慢。因此,实际使用中,常常将对称加密和非对称加密结合使用,即使用非对称加密协商对称加密的密钥,使用对称加密密钥加密传输内容。

6.RSA项目中加密源码

6.1生成随机公钥私钥

随机生成公钥和私钥,用于测试RSA加密解密
 /**
     * 私钥
     */
    private static RSAPrivateKey privateKey;
    /**
     * 公钥
     */
    private static RSAPublicKey publicKey;

    /**
     * 随机生成密钥对
     */
    public static void genKeyPair() {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        keyPairGen.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGen.generateKeyPair();
        privateKey = (RSAPrivateKey) keyPair.getPrivate();
        publicKey = (RSAPublicKey) keyPair.getPublic();
    }

6.2加载公钥/私钥

从字符串/文件输入流中加载公钥

    /**
     * 从字符串中加载公钥
     *
     * @param publicKeyStr 公钥数据字符串
     * @throws Exception 加载公钥时产生的异常
     */
    public static void loadPublicKey(String publicKeyStr) throws Exception {
        try {
            byte[] buffer = EnDecryptionUtil.base64Decode(publicKeyStr);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
            publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("公钥非法");
        } catch (NullPointerException e) {
            throw new Exception("公钥数据为空");
        }
    }
    /**
     * 从文件输入流中加载公钥
     *
     * @param in 公钥输入流
     * @throws Exception 加载公钥时产生的异常
     */
    public static void loadPublicKey(InputStream in) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            loadPublicKey(sb.toString());
        } catch (IOException e) {
            throw new Exception("公钥数据流读取错误");
        } catch (NullPointerException e) {
            throw new Exception("公钥输入流为空");
        }
    }
//从字符串/文件输入流中加载私钥
    /**
     * 从字符串中加载私钥
     * @param privateKeyStr
     * @throws Exception
     */
    public static void loadPrivateKey(String privateKeyStr) throws Exception {
        try {
            byte[] buffer = EnDecryptionUtil.base64Decode(privateKeyStr);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("私钥非法");
        } catch (NullPointerException e) {
            throw new Exception("私钥数据为空");
        }
    }
    /**
     * 从文件输入流中加载私钥
     *
     * @param in 私钥输入流
     * @return 是否成功
     * @throws Exception
     */
    public static void loadPrivateKey(InputStream in) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            loadPrivateKey(sb.toString());
        } catch (IOException e) {
            throw new Exception("私钥数据读取错误");
        } catch (NullPointerException e) {
            throw new Exception("私钥输入流为空");
        }
    }

6.3RSA加密数据

    /**
     * RSA加密过程
     *
     * @param publicKey     公钥
     * @param plainTextData 明文数据
     * @return
     * @throws Exception 加密过程中的异常信息
     */
    public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
        if (publicKey == null) {
            throw new Exception("加密公钥为空, 请设置");
        }
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return cipher.doFinal(plainTextData);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此加密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("加密公钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("明文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("明文数据已损坏");
        }
    }
//加密后获得的byte[]数组一般会进行Base64编码

6.4RSA解密

    /**
     * RSA解密
     *
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return 明文
     * @throws Exception 解密过程中的异常信息
     */
    public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
        if (privateKey == null) {
            throw new Exception("解密私钥为空, 请设置");
        }
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return cipher.doFinal(cipherData);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此解密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("解密私钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("密文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("密文数据已损坏");
        }
    }
//如果输入的密文进行过Base64编码,需Base64解码后再进行RSA解密

6.4RSA 运行结果

公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO2TVhB1VIpUhNb5+owamkjmU8dNEMJyTbakBT
    b7GysKaA+byMRqJLRAbVPj+eD15erREOkv9A1z4mOMo7i+7hb6J8LuktCDWC5QeusvbwlpOjjIE6
    Sq8pETHPnHX5dd+ORFYWPrbd7drSIv0Fbm3R7zi0LhuJn3JWkLf1JEFDywIDAQAB
私钥:MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAM7ZNWEHVUilSE1vn6jBqaSOZTx0
    0QwnJNtqQFNvsbKwpoD5vIxGoktEBtU+P54PXl6tEQ6S/0DXPiY4yjuL7uFvonwu6S0INYLlB66y
    9vCWk6OMgTpKrykRMc+cdfl1345EVhY+tt3t2tIi/QVubdHvOLQuG4mfclaQt/UkQUPLAgMBAAEC
    gYB+M3Xm4iN9dCI95JnDy4ymMp6/mQImaQeKuzPN9Dq1rCOaU0RfTYUdaL7GgfkshXHtT6g1fSgx
    NmHbzhBM7l5qoYJNwz/8KQ9rTphdc0JQFzu3ECkDZvOe+yjSKWpuZFGizLsB2j3Og4MF3fOKNfN7
    c1ucNNEYpzbGPyOPC23TWQJBAPOU5pLEwMV4VSC3LgJcjorvf5DQqJVpnPYyHRE7MFhsnVHfmbIq
    nTBhOcdomwOde+yQjerGIi7W7RIjobgoZdUCQQDZZOLEo5qdIXn319R3ucPsAHLPcTa8kfxpUHLo
    rN8INKUj7dR3FtWc9cye5fzWRg+NkBx6OC408l95qeGvBbMfAkEAqQJ7DgFJBHtfDcksOmVAXnSZ
    XcD6CFn0l/rjok4gWGpcqi9stGvPD3+WmJ8jV9nQ367ZWbpKg5eLfReOIXqeVQJBAMuxwuVbIoE+
    n8kBm1w/XHuig/EpdI9F/oszTSgE6soGggHjU6PuamMy0PLGLp0bcnFDadt/DpSf0aPu8L8NCSMC
    QQDvL5cjxQqIPJSP1T+JKktvd+nWPULt7Adir1fab022e0XfEod73Eoo4rp0GmN0hSZUH0VBBvqf
    lNY1P23tZP3C

待加密明文:123456
加密后Base64数据:KMzWgXeWLpc31/D3LOv65AYquARkNCoPNVy+vqZd4ASC8hev1iZtBOowmWp5mMr0pYHya9AK6Ang
    GZmT2KzS472r+UR6LJxY7u3qthGuWiWcWmZbyH/z2LEB6du60b8BOpa670GE/HB074z85kPTWCWE
    3kvBNDbYvDdfjMD/8JY=

待解密Base64密文:KMzWgXeWLpc31/D3LOv65AYquARkNCoPNVy+vqZd4ASC8hev1iZtBOowmWp5mMr0pYHya9AK6Ang
    GZmT2KzS472r+UR6LJxY7u3qthGuWiWcWmZbyH/z2LEB6du60b8BOpa670GE/HB074z85kPTWCWE
    3kvBNDbYvDdfjMD/8JY=
解密后数据:123456

总结:

公钥加密、私钥解密、私钥签名、公钥验签。

想要源码评论区回复我,给你私发链接

Kotlin基础篇【1】Android Studio 3.0 Kotlin环境配置
Kotlin基础篇【2】初识Kotlin的意义
Kotlin基础篇【3】Kotlin基础语法

=======Kotlin基础篇【4】Kotlin基础语法即将更新=======

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

推荐阅读更多精彩内容