IOS & JAVA RSA Encryption & Decryption

 

  在网上找了许多篇关于RSA加密解密的文章与博客,是很有帮助,但比较零散与不简洁。

  (至于RSA的基本原理,大家可以看 阮一峰的网络日志 的 RSA算法原理(一) 和 RSA算法原理(二) )

  这篇文章只是做一个整理,帮大家理清一下步骤的而已( 英文版本请看 RSA Encrypt and Decrypt in IOS and JAVA )。

 

  一、首先,打开Terminal, 生成必要的公钥、私钥、证书:

  

复制代码
openssl genrsa -out private_key.pem 1024

openssl req -new -key private_key.pem -out rsaCertReq.csr

openssl x509 -req -days 36500 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt

openssl x509 -outform der -in rsaCert.crt -out public_key.der               // Create public_key.der For IOS
 
openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt  // Create private_key.p12 For IOS. 这一步,请记住你输入的密码,IOS代码里会用到

openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout             // Create rsa_public_key.pem For Java
 
openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt     // Create pkcs8_private_key.pem For Java
复制代码

 

  上面七个步骤,总共生成7个文件。其中 public_key.der 和 private_key.p12 这对公钥私钥是给IOS用的, rsa_public_key.pem 和 pkcs8_private_key.pem 是给JAVA用的。

  它们的源都来自一个私钥:private_key.pem , 所以IOS端加密的数据,是可以被JAVA端解密的,反过来也一样。

 

  二、IOS 端:

  2017.0306更新,文章过时了啦,大家请参考一个大神的Github: Objective-C-RSA 

 

  三、 JAVA 端:

  RSAEncryptor.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
package com.modules.Encryptor;
 
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
 
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
 
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
public class RSAEncryptor {
 
     
    public static void main(String[] args){ 
         
        String privateKeyPath = "/Users/Love/Desktop/RSA_KEYS/rsa_public_key.pem";        // replace your public key path here
        String publicKeyPath =  "/Users/Love/Desktop/RSA_KEYS/pkcs8_private_key.pem";     // replace your private path here
        RSAEncryptor rsaEncryptor = new RSAEncryptor(privateKeyPath, publicKeyPath);
 
        try {
             
            String test = "JAVA";
            String testRSAEnWith64 = rsaEncryptor.encryptWithBase64(test);
            String testRSADeWith64 = rsaEncryptor.decryptWithBase64(testRSAEnWith64);
            System.out.println("\nEncrypt: \n" + testRSAEnWith64);
            System.out.println("\nDecrypt: \n" + testRSADeWith64);
             
            // NSLog the encrypt string from Xcode , and paste it here.
            // 请粘贴来自IOS端加密后的字符串
//            String rsaBase46StringFromIOS =
//                    "nIIV7fVsHe8QquUbciMYbbumoMtbBuLsCr2yMB/WAhm+S/kGRPlf+k2GH8imZIYQ" + "\r" +
//                    "QBDssVLQmS392QlxS87hnwMRJIzWw6vdRv/k79TgTfu6tI/9QTqIOvNlQIqtIcVm" + "\r" +
//                    "R/suvydoymKgdlB+ce5/tHSxfqEOLLrL1Zl2PqJSP4A=";
//           
//            String decryptStringFromIOS = rsaEncryptor.decryptWithBase64(rsaBase46StringFromIOS);
//            System.out.println("Decrypt result from ios client: \n" + decryptStringFromIOS);
             
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
 
 
 
 
 
    /**
     * @param publicKeyFilePath    
     * @param privateKeyFilePath   
     */
    public RSAEncryptor(String publicKeyFilePath, String privateKeyFilePath) throws Exception {
        String public_key = getKeyFromFile(publicKeyFilePath);
        String private_key = getKeyFromFile(privateKeyFilePath);
        loadPublicKey(public_key); 
        loadPrivateKey(private_key); 
    }
    public RSAEncryptor() {
        // load the PublicKey and PrivateKey manually
    }
     
     
    public String getKeyFromFile(String filePath) throws Exception {
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
         
        String line = null;
        List<String> list = new ArrayList<String>();
        while ((line = bufferedReader.readLine()) != null){
            list.add(line);
        }
         
        // remove the firt line and last line
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 1; i < list.size() - 1; i++) {
            stringBuilder.append(list.get(i)).append("\r");
        }
         
        String key = stringBuilder.toString();
        return key;
    }
     
    public String decryptWithBase64(String base64String) throws Exception {
        //  http://commons.apache.org/proper/commons-codec/ : org.apache.commons.codec.binary.Base64
        // sun.misc.BASE64Decoder
        byte[] binaryData = decrypt(getPrivateKey(), new BASE64Decoder().decodeBuffer(base64String) /*org.apache.commons.codec.binary.Base64.decodeBase64(base46String.getBytes())*/);
        String string = new String(binaryData);
        return string;
    }
     
    public String encryptWithBase64(String string) throws Exception {
        //  http://commons.apache.org/proper/commons-codec/ : org.apache.commons.codec.binary.Base64
        // sun.misc.BASE64Encoder
        byte[] binaryData = encrypt(getPublicKey(), string.getBytes());
        String base64String = new BASE64Encoder().encodeBuffer(binaryData) /* org.apache.commons.codec.binary.Base64.encodeBase64(binaryData) */;
        return base64String;
    }
   
     
     
    // convenient properties
    public static RSAEncryptor sharedInstance = null;
    public static void setSharedInstance (RSAEncryptor rsaEncryptor) {
        sharedInstance = rsaEncryptor;
    }
     
     
     
     
    // From: http://blog.csdn.net/chaijunkun/article/details/7275632
 
    /**
     * 私钥
     */ 
    private RSAPrivateKey privateKey; 
   
    /**
     * 公钥
     */ 
    private RSAPublicKey publicKey; 
       
    /**
     * 获取私钥
     * @return 当前的私钥对象
     */ 
    public RSAPrivateKey getPrivateKey() { 
        return privateKey; 
    
   
    /**
     * 获取公钥
     * @return 当前的公钥对象
     */ 
    public RSAPublicKey getPublicKey() { 
        return publicKey; 
    
   
    /**
     * 随机生成密钥对
     */ 
    public void genKeyPair(){ 
        KeyPairGenerator keyPairGen= null
        try
            keyPairGen= KeyPairGenerator.getInstance("RSA"); 
        } catch (NoSuchAlgorithmException e) { 
            e.printStackTrace(); 
        
        keyPairGen.initialize(1024, new SecureRandom()); 
        KeyPair keyPair= keyPairGen.generateKeyPair(); 
        this.privateKey= (RSAPrivateKey) keyPair.getPrivate(); 
        this.publicKey= (RSAPublicKey) keyPair.getPublic(); 
    
   
    /**
     * 从文件中输入流中加载公钥
     * @param in 公钥输入流
     * @throws Exception 加载公钥时产生的异常
     */ 
    public 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 publicKeyStr 公钥数据字符串
     * @throws Exception 加载公钥时产生的异常
     */ 
    public void loadPublicKey(String publicKeyStr) throws Exception{ 
        try
            BASE64Decoder base64Decoder= new BASE64Decoder(); 
            byte[] buffer= base64Decoder.decodeBuffer(publicKeyStr);
            KeyFactory keyFactory= KeyFactory.getInstance("RSA"); 
            X509EncodedKeySpec keySpec= new X509EncodedKeySpec(buffer); 
            this.publicKey= (RSAPublicKey) keyFactory.generatePublic(keySpec); 
        } catch (NoSuchAlgorithmException e) { 
            throw new Exception("无此算法"); 
        } catch (InvalidKeySpecException e) { 
            throw new Exception("公钥非法"); 
        } catch (IOException e) { 
            throw new Exception("公钥数据内容读取错误"); 
        } catch (NullPointerException e) { 
            throw new Exception("公钥数据为空"); 
        
    
   
    /**
     * 从文件中加载私钥
     * @param keyFileName 私钥文件名
     * @return 是否成功
     * @throws Exception 
     */ 
    public 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("私钥输入流为空"); 
        
    
   
    public void loadPrivateKey(String privateKeyStr) throws Exception{ 
        try
            BASE64Decoder base64Decoder= new BASE64Decoder(); 
            byte[] buffer= base64Decoder.decodeBuffer(privateKeyStr); 
            PKCS8EncodedKeySpec keySpec= new PKCS8EncodedKeySpec(buffer); 
            KeyFactory keyFactory= KeyFactory.getInstance("RSA"); 
            this.privateKey= (RSAPrivateKey) keyFactory.generatePrivate(keySpec); 
        } catch (NoSuchAlgorithmException e) { 
            throw new Exception("无此算法"); 
        } catch (InvalidKeySpecException e) { 
            e.printStackTrace();
            throw new Exception("私钥非法"); 
        } catch (IOException e) { 
            throw new Exception("私钥数据内容读取错误"); 
        } catch (NullPointerException e) { 
            throw new Exception("私钥数据为空"); 
        
    
   
    /**
     * 加密过程
     * @param publicKey 公钥
     * @param plainTextData 明文数据
     * @return
     * @throws Exception 加密过程中的异常信息
     */ 
    public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception{ 
        if(publicKey== null){ 
            throw new Exception("加密公钥为空, 请设置"); 
        
        Cipher cipher= null
        try
            cipher= Cipher.getInstance("RSA");//, new BouncyCastleProvider()); 
            cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
            byte[] output= cipher.doFinal(plainTextData); 
            return output; 
        } 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("明文数据已损坏"); 
        
    
   
    /**
     * 解密过程
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return 明文
     * @throws Exception 解密过程中的异常信息
     */ 
    public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception{ 
        if (privateKey== null){ 
            throw new Exception("解密私钥为空, 请设置"); 
        
        Cipher cipher= null
        try
            cipher= Cipher.getInstance("RSA");//, new BouncyCastleProvider()); 
            cipher.init(Cipher.DECRYPT_MODE, privateKey); 
            byte[] output= cipher.doFinal(cipherData); 
            return output; 
        } 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("密文数据已损坏"); 
        }        
    
   
     
     
    /**
     * 字节数据转字符串专用集合
     */ 
    private static final char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
     
    /**
     * 字节数据转十六进制字符串
     * @param data 输入数据
     * @return 十六进制内容
     */ 
    public static String byteArrayToString(byte[] data){ 
        StringBuilder stringBuilder= new StringBuilder(); 
        for (int i=0; i<data.length; i++){ 
            //取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移 
            stringBuilder.append(HEX_CHAR[(data[i] & 0xf0)>>> 4]); 
            //取出字节的低四位 作为索引得到相应的十六进制标识符 
            stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]); 
            if (i<data.length-1){ 
                stringBuilder.append(' '); 
            
        
        return stringBuilder.toString(); 
    
 
 

  

 

posted @   makemelike  阅读(7438)  评论(11编辑  收藏  举报
编辑推荐:
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
阅读排行:
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· Vite CVE-2025-30208 安全漏洞
· 《HelloGitHub》第 108 期
· MQ 如何保证数据一致性?
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
点击右上角即可分享
微信分享提示