中文用于网络传输要先用 java.net.URLEncoder 的encode方法加密再调用你自己的加密方法。
反过来,接收到密文的时候在调用自己的解密方法解密后需再调用 java.net.URLDecoder 解密,这样中文就正常了
2. 关于IOS客户端使用AES加密(解密),云端java实现加密(解密)不一致的问题。
对AES不了解,但可以考虑将解密作个DLL,java的jni机制调用。。。
3. ios开发中aes加密填充字节iv怎么填充
之前在项目上用到AES256加密解密算法,刚开始在java端加密解密都没有问题,在iOS端加密解密也没有问题。但是奇怪的是在java端加密后的文件在iOS端无法正确解密打开,然后简单测试了一下,发现在java端和iOS端采用相同明文,相同密钥加密后的密文不一样!上网查了资料后发现iOS中AES加密算法采用的填充是PKCS7Padding,而java不支持PKCS7Padding,只支持PKCS5Padding。我们知道加密算法由算法+模式+填充组成,所以这两者不同的填充算法导致相同明文相同密钥加密后出现密文不一致的情况。那么我们需要在java中用PKCS7Padding来填充,这样就可以和iOS端填充算法一致了。
要实现在java端用PKCS7Padding填充,需要用到bouncycastle组件来实现,下面我会提供该包的下载。啰嗦了一大堆,下面是一个简单的测试,上代码!
001 package com.encrypt.file;
002
003
004 import java.io.UnsupportedEncodingException;
005 importjava.security.Key;
006 import java.security.Security;
007
008 importjavax.crypto.Cipher;
009 importjavax.crypto.SecretKey;
010 importjavax.crypto.spec.SecretKeySpec;
011
012 public classAES256Encryption{
013
014 /**
015 * 密钥算法
016 * java6支持56位密钥,bouncycastle支持64位
017 * */
018 public static finalString KEY_ALGORITHM="AES";
019
020 /**
021 * 加密/解密算法/工作模式/填充方式
022 *
023 * JAVA6 支持PKCS5PADDING填充方式
024 * Bouncy castle支持PKCS7Padding填充方式
025 * */
026 public static finalString CIPHER_ALGORITHM="AES/ECB/PKCS7Padding";
027
028 /**
029 *
030 * 生成密钥,java6只支持56位密钥,bouncycastle支持64位密钥
031 * @return byte[] 二进制密钥
032 * */
033 public static byte[] initkey() throwsException{
034
035 // //实例化密钥生成器
036 // Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
037 // KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM, "BC");
038 // //初始化密钥生成器,AES要求密钥长度为128位、192位、256位
039 //// kg.init(256);
040 // kg.init(128);
041 // //生成密钥
042 // SecretKey secretKey=kg.generateKey();
043 // //获取二进制密钥编码形式
044 // return secretKey.getEncoded();
045 //为了便于测试,这里我把key写死了,如果大家需要自动生成,可用上面注释掉的代码
046 return new byte[] { 0x08, 0x08, 0x04, 0x0b, 0x02, 0x0f, 0x0b, 0x0c,
047 0x01, 0x03, 0x09, 0x07, 0x0c, 0x03, 0x07, 0x0a, 0x04, 0x0f,
048 0x06, 0x0f, 0x0e, 0x09, 0x05, 0x01, 0x0a, 0x0a, 0x01, 0x09,
049 0x06, 0x07, 0x09, 0x0d };
050 }
051
052 /**
053 * 转换密钥
054 * @param key 二进制密钥
055 * @return Key 密钥
056 * */
057 public static Key toKey(byte[] key) throwsException{
058 //实例化DES密钥
059 //生成密钥
060 SecretKey secretKey=newSecretKeySpec(key,KEY_ALGORITHM);
061 returnsecretKey;
062 }
063
064 /**
065 * 加密数据
066 * @param data 待加密数据
067 * @param key 密钥
068 * @return byte[] 加密后的数据
069 * */
070 public static byte[] encrypt(byte[] data,byte[] key) throwsException{
071 //还原密钥
072 Key k=toKey(key);
073 /**
074 * 实例化
075 * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现
076 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
077 */
078 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
079 Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC");
080 //初始化,设置为加密模式
081 cipher.init(Cipher.ENCRYPT_MODE, k);
082 //执行操作
083 returncipher.doFinal(data);
084 }
085 /**
086 * 解密数据
087 * @param data 待解密数据
088 * @param key 密钥
089 * @return byte[] 解密后的数据
090 * */
091 public static byte[] decrypt(byte[] data,byte[] key) throwsException{
092 //欢迎密钥
093 Key k =toKey(key);
094 /**
095 * 实例化
096 * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现
097 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
098 */
099 Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
100 //初始化,设置为解密模式
101 cipher.init(Cipher.DECRYPT_MODE, k);
102 //执行操作
103 returncipher.doFinal(data);
104 }
105 /**
106 * @param args
107 * @throws UnsupportedEncodingException
108 * @throws Exception
109 */
110 public static void main(String[] args) {
111
112 String str="AES";
113 System.out.println("原文:"+str);
114
115 //初始化密钥
116 byte[] key;
117 try {
118 key = AES256Encryption.initkey();
119 System.out.print("密钥:");
120 for(int i = 0;i<key.length;i++){
121 System.out.printf("%x", key[i]);
122 }
123 System.out.print("\n");
124 //加密数据
125 byte[] data=AES256Encryption.encrypt(str.getBytes(), key);
126 System.out.print("加密后:");
127 for(int i = 0;i<data.length;i++){
128 System.out.printf("%x", data[i]);
129 }
130 System.out.print("\n");
131
132 //解密数据
133 data=AES256Encryption.decrypt(data, key);
134 System.out.println("解密后:"+newString(data));
135 } catch (Exception e) {
136 // TODO Auto-generated catch block
137 e.printStackTrace();
138 }
139
140 }
141 }
4. JAVA和IOS区别是什么
安卓和ios要比java先进很多。java是一个编程语言,手机支持java是指的支持用java语言写成的程序,算不上智能系统。安卓和ios最大的区别就是品牌范围。安卓是开源系统,因此很多厂商用,用户多,应用程序数量也在增长,已经超过了ios,这个系统最大的好处就是不用花钱买应用,都是免费的,但是系统与程序兼容性不好,因为各个厂商的手机配置不一样,性能不一样,程序编写技术员很难做到让每个手机都能匹配合适,因此,如果要用安卓的手机,就选大品牌的或者是销量领先的,以保证兼容问题。
5. java如何用Aes加密和解密
你解密的key必须是加密的key啊
你看看,你解密的时候又KeyGenerator.getInstance("AES").generateKey();这是重新搞了一个key啊,当然解不出来了
我估计你这代码人家原先是写在一起的吧,加密完了再直接解密给你看,人家只generateKey一次,自然很顺利,你分成了两个例子,居然分别generateKey,自然失败
6. 关于iOS aes256加密的问题,请各位帮忙,搞了一个星期,急求答案!
之前在项目上用到AES256加密解密算法,刚开始在java端加密解密都没有问题,在iOS端加密解密也没有问题。但是奇怪的是在java端加密后的文件在iOS端无法正确解密打开,然后简单测试了一下,发现在java端和iOS端采用相同明文,相同密钥加密后的密文不一样!上网查了资料后发现iOS中AES加密算法采用的填充是PKCS7Padding,而java不支持PKCS7Padding,只支持PKCS5Padding。我们知道加密算法由算法+模式+填充组成,所以这两者不同的填充算法导致相同明文相同密钥加密后出现密文不一致的情况。那么我们需要在java中用PKCS7Padding来填充,这样就可以和iOS端填充算法一致了。
要实现在java端用PKCS7Padding填充,需要用到bouncycastle组件来实现,下面我会提供该包的下载。啰嗦了一大堆,下面是一个简单的测试,上代码!
001 package com.encrypt.file;
002
003
004 import java.io.UnsupportedEncodingException;
005 importjava.security.Key;
006 import java.security.Security;
007
008 importjavax.crypto.Cipher;
009 importjavax.crypto.SecretKey;
010 importjavax.crypto.spec.SecretKeySpec;
011
012 public classAES256Encryption{
013
014 /**
015 * 密钥算法
016 * java6支持56位密钥,bouncycastle支持64位
017 * */
018 public static finalString KEY_ALGORITHM="AES";
019
020 /**
021 * 加密/解密算法/工作模式/填充方式
022 *
023 * JAVA6 支持PKCS5PADDING填充方式
024 * Bouncy castle支持PKCS7Padding填充方式
025 * */
026 public static finalString CIPHER_ALGORITHM="AES/ECB/PKCS7Padding";
027
028 /**
029 *
030 * 生成密钥,java6只支持56位密钥,bouncycastle支持64位密钥
031 * @return byte[] 二进制密钥
032 * */
033 public static byte[] initkey() throwsException{
034
035 // //实例化密钥生成器
036 // Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
037 // KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM, "BC");
038 // //初始化密钥生成器,AES要求密钥长度为128位、192位、256位
039 //// kg.init(256);
040 // kg.init(128);
041 // //生成密钥
042 // SecretKey secretKey=kg.generateKey();
043 // //获取二进制密钥编码形式
044 // return secretKey.getEncoded();
045 //为了便于测试,这里我把key写死了,如果大家需要自动生成,可用上面注释掉的代码
046 return new byte[] { 0x08, 0x08, 0x04, 0x0b, 0x02, 0x0f, 0x0b, 0x0c,
047 0x01, 0x03, 0x09, 0x07, 0x0c, 0x03, 0x07, 0x0a, 0x04, 0x0f,
048 0x06, 0x0f, 0x0e, 0x09, 0x05, 0x01, 0x0a, 0x0a, 0x01, 0x09,
049 0x06, 0x07, 0x09, 0x0d };
050 }
051
052 /**
053 * 转换密钥
054 * @param key 二进制密钥
055 * @return Key 密钥
056 * */
057 public static Key toKey(byte[] key) throwsException{
058 //实例化DES密钥
059 //生成密钥
060 SecretKey secretKey=newSecretKeySpec(key,KEY_ALGORITHM);
061 returnsecretKey;
062 }
063
064 /**
065 * 加密数据
066 * @param data 待加密数据
067 * @param key 密钥
068 * @return byte[] 加密后的数据
069 * */
070 public static byte[] encrypt(byte[] data,byte[] key) throwsException{
071 //还原密钥
072 Key k=toKey(key);
073 /**
074 * 实例化
075 * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现
076 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
077 */
078 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
079 Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC");
080 //初始化,设置为加密模式
081 cipher.init(Cipher.ENCRYPT_MODE, k);
082 //执行操作
083 returncipher.doFinal(data);
084 }
085 /**
086 * 解密数据
087 * @param data 待解密数据
088 * @param key 密钥
089 * @return byte[] 解密后的数据
090 * */
091 public static byte[] decrypt(byte[] data,byte[] key) throwsException{
092 //欢迎密钥
093 Key k =toKey(key);
094 /**
095 * 实例化
096 * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现
097 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
098 */
099 Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
100 //初始化,设置为解密模式
101 cipher.init(Cipher.DECRYPT_MODE, k);
102 //执行操作
103 returncipher.doFinal(data);
104 }
105 /**
106 * @param args
107 * @throws UnsupportedEncodingException
108 * @throws Exception
109 */
110 public static void main(String[] args) {
111
112 String str="AES";
113 System.out.println("原文:"+str);
114
115 //初始化密钥
116 byte[] key;
117 try {
118 key = AES256Encryption.initkey();
119 System.out.print("密钥:");
120 for(int i = 0;i<key.length;i++){
121 System.out.printf("%x", key[i]);
122 }
123 System.out.print("\n");
124 //加密数据
125 byte[] data=AES256Encryption.encrypt(str.getBytes(), key);
126 System.out.print("加密后:");
127 for(int i = 0;i<data.length;i++){
128 System.out.printf("%x", data[i]);
129 }
130 System.out.print("\n");
131
132 //解密数据
133 data=AES256Encryption.decrypt(data, key);
134 System.out.println("解密后:"+newString(data));
135 } catch (Exception e) {
136 // TODO Auto-generated catch block
137 e.printStackTrace();
138 }
139
140 }
141 }
运行程序后的结果截图:
ViewController.m文件
01 //
02 // ViewController.m
03 // AES256EncryptionDemo
04 //
05 // Created by 孙 裔 on 12-12-13.
06 // Copyright (c) 2012年 rich sun. All rights reserved.
07 //
08
09 #import "ViewController.h"
10 #import "EncryptAndDecrypt.h"
11
12 @interface ViewController ()
13
14 @end
15
16 @implementation ViewController
17 @synthesize plainTextField;
18 - (void)viewDidLoad
19 {
20 [super viewDidLoad];
21 // Do any additional setup after loading the view, typically from a nib.
22 }
23
24 - (void)didReceiveMemoryWarning
25 {
26 [super didReceiveMemoryWarning];
27 // Dispose of any resources that can be recreated.
28 }
29 //这个函数实现了用户输入完后点击视图背景,关闭键盘
30 - (IBAction)backgroundTap:(id)sender{
31 [plainTextField resignFirstResponder];
32 }
33
34 - (IBAction)encrypt:(id)sender {
35
36 NSString *plainText = plainTextField.text;//明文
37 NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
38
39 //为了测试,这里先把密钥写死
40 Byte keyByte[] = {0x08,0x08,0x04,0x0b,0x02,0x0f,0x0b,0x0c,0x01,0x03,0x09,0x07,0x0c,0x03,
41 0x07,0x0a,0x04,0x0f,0x06,0x0f,0x0e,0x09,0x05,0x01,0x0a,0x0a,0x01,0x09,
42 0x06,0x07,0x09,0x0d};
43 //byte转换为NSData类型,以便下边加密方法的调用
44 NSData *keyData = [[NSData alloc] initWithBytes:keyByte length:32];
45 //
46 NSData *cipherTextData = [plainTextData AES256EncryptWithKey:keyData];
47 Byte *plainTextByte = (Byte *)[cipherTextData bytes];
48 for(int i=0;i<[cipherTextData length];i++){
49 printf("%x",plainTextByte[i]);
50 }
51
52 }
53 @end
附上出处链接:http://blog.csdn.net/pjk1129/article/details/8489550
7. android,java 通用的加密解密方式有几种
移动端越来越火了,我们在开发过程中,总会碰到要和移动端打交道的场景,比如.NET和android或者iOS的打交道。为了让数据交互更安全,我们需要对数据进行加密传输。今天研究了一下,把几种语言的加密都实践了一遍,实现了.NET,java(android),iOS都同一套的加密算法,下面就分享给大家。
AES加密有多种算法模式,下面提供两套模式的可用源码。
加密方式:
先将文本AES加密
返回Base64转码
解密方式:
将数据进行Base64解码
进行AES解密
一、CBC(Cipher Block Chaining,加密块链)模式
是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度.
密钥
密钥偏移量
java/adroid加密AESOperator类:
package com.bci.wx.base.util;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* AES 是一种可逆加密算法,对用户的敏感信息加密处理 对原始数据进行AES加密后,在进行Base64编码转化;
*/
public class AESOperator {
/*
* 加密用的Key 可以用26个字母和数字组成 此处使用AES-128-CBC加密模式,key需要为16位。
*/
private String sKey = "smkldospdosldaaa";//key,可自行修改
private String ivParameter = "0392039203920300";//偏移量,可自行修改
private static AESOperator instance = null;
private AESOperator() {
}
public static AESOperator getInstance() {
if (instance == null)
instance = new AESOperator();
return instance;
}
public static String Encrypt(String encData ,String secretKey,String vector) throws Exception {
if(secretKey == null) {
return null;
}
if(secretKey.length() != 16) {
return null;
}
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] raw = secretKey.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(encData.getBytes("utf-8"));
return new BASE64Encoder().encode(encrypted);// 此处使用BASE64做转码。
}
// 加密
public String encrypt(String sSrc) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] raw = sKey.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
return new BASE64Encoder().encode(encrypted);// 此处使用BASE64做转码。
}
// 解密
public String decrypt(String sSrc) throws Exception {
try {
byte[] raw = sKey.getBytes("ASCII");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);// 先用base64解密
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original, "utf-8");
return originalString;
} catch (Exception ex) {
return null;
}
}
public String decrypt(String sSrc,String key,String ivs) throws Exception {
try {
byte[] raw = key.getBytes("ASCII");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(ivs.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);// 先用base64解密
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original, "utf-8");
return originalString;
} catch (Exception ex) {
return null;
}
}
public static String encodeBytes(byte[] bytes) {
StringBuffer strBuf = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
}
return strBuf.toString();
}
8. ios aes解密为空是怎么回事
那应该是你加密的出错了,你在看看你加密的方法和解密的方法是否一致
9. 通过Java如何实现AES密码算法
1. AES加密字符串
public static byte[] encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
// 128位的key生产者
//加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
// null。
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return result;
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
2. AES解密
public static byte[] decrypt(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
byte[] result = cipher.doFinal(content);
return result; // 明文
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
10. java rsa证书 ios 支持吗
了之前三个终端进行AES加解密的经验,实现RSA加解密倒不是太复杂。两个关键点:1)RSA需要密钥文件,且密钥文件的格式很重要;2)padding方式需要一致,比较被广泛支持且被很多RAS实现设置为默认padding方式的是PKCS1PADDING V1.5,建议采用。
我是在linux下用openssl生成公钥、私钥文件的,分三个步骤,命令如下:
1、生成公钥public_key.der 和 私钥private_key.pem(加密)
openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem
按照提示,填入私钥的密码,签名证书的组织名、邮件等信息之后,就会生成包含有公钥的证书文件public_key.der和私钥文件private_key.pem。public_key.der文件用于分发到ios客户端进行公钥加密。
2、生成公钥public_key.pem。
openssl rsa -in private_key.pem -pubout -out public_key.pem ,这步生成的public_key.pem用于分发到c++客户端和安卓客户端进行公钥加密。
3、将私钥 private_key.pem(加密)转换为PKCS#8编码格式(且不加密)。
openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt
这步生成的pkcs8_private_key.pem用于在Java服务端进行私钥解密。
RSA的一般用法是在客户端用公钥加密,在网络上传输密文,然后服务端用私钥解密获取原文。所以RSA实现都会支持公钥加密、私钥解密。反过来用私钥加密然后公钥解密,理论上也是可行的。不过我没有试过。如果决定要这么做,祝君好运。
注意:RSA提供的API不像AES,不会自动分块处理。需要手动将原文切割为128-11的块去进行加密 (128是因为采用RSA1024,128=1024/8, 11是因为padding采用版本1.5的PKCS1PADDING。这种分块方式是多个RSA实现的默认方式,推荐使用),每次加密输出的密文长度均是128字节(RSA1024),把这些密文顺序拼装起来。在解密的时候,则是将密文按128字节进行切割,解密后再拼装在一起即可。
======================C++客户端公钥加密=======================
使用大名鼎鼎openssl类库实现,感慨下其API设计得真烂。。。。
注意:虽然输入和输出都是std::string,但不要理解成字符串,实际上都是二进制数据。另外公钥得保存在文件中,我还没找到使用内存中公钥的方法,但对我已经够用了。
std::string EvpHelper::rsaEncryptUsingPublicKeyFile(const std::string& source, const std::string& keyFile)
{
std::string result;
BIO* bp = NULL;
EVP_PKEY* key = NULL;
RSA* rsa = NULL;
EVP_PKEY_CTX* ctx = NULL;
unsigned char* encryptedData = NULL;
try
{
// load public key
OpenSSL_add_all_algorithms();
bp = BIO_new(BIO_s_file());
if (bp == NULL)
{
throw std::runtime_error("BIO_new failed.");
}
if (BIO_read_filename(bp, keyFile.c_str()) <= 0)
{
throw std::runtime_error("BIO_read_filename failed.");
}
rsa = PEM_read_bio_RSA_PUBKEY(bp, NULL, NULL, NULL);
if (rsa == NULL)
{
throw std::runtime_error("PEM_read_bio_RSA_PUBKEY failed.");
}
key = EVP_PKEY_new();
if (key == NULL)
{
throw std::runtime_error("EVP_PKEY_new failed.");
}
EVP_PKEY_assign_RSA(key, rsa);
rsa = NULL;
// encrypt
OpenSSL_add_all_ciphers();
ctx = EVP_PKEY_CTX_new(key, NULL);
if (ctx == NULL)
{
throw std::runtime_error("EVP_PKEY_CTX_new failed.");
}
if (EVP_PKEY_encrypt_init(ctx) <= 0)
{
throw std::runtime_error("EVP_PKEY_encrypt_init failed.");
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
{
throw std::runtime_error("EVP_PKEY_CTX_set_rsa_padding failed.");
}
encryptedData = new unsigned char[source.size() * 2];
size_t encryptedDataLen = 0;
size_t BLOCK_SIZE = 128 - 11;
size_t sourceDataLen = (int)source.size();
for (size_t i = 0; i < sourceDataLen; i += BLOCK_SIZE)
{
size_t leftBytes = sourceDataLen - i;
size_t sourceBlockLen = (leftBytes <= BLOCK_SIZE) ? leftBytes : BLOCK_SIZE;
size_t encryptedBlockLen = 128;
if(EVP_PKEY_encrypt(ctx, (encryptedData + encryptedDataLen), &encryptedBlockLen,
(const unsigned char *)(source.data() + i), sourceBlockLen) <= 0)
{
throw std::runtime_error("EVP_PKEY_encrypt failed.");
}
encryptedDataLen += encryptedBlockLen;
}
result = std::string((char*)encryptedData, encryptedDataLen);
}
catch (const std::exception& e)
{
LErr(e.what());
}
if (bp != NULL)
{
LInfoCMD(BIO_free(bp));
}
if(rsa != NULL)
{
LInfoCMD(RSA_free(rsa));
}
if (ctx != NULL)
{
LInfoCMD(EVP_PKEY_CTX_free(ctx));
}
if (key != NULL)
{
LInfoCMD(EVP_PKEY_free(key));
}
if (encryptedData != NULL)
{
delete[] encryptedData;
}
return result;
}
======================Java客户端公钥加密=======================
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
public class RSAEncrypt {
public static RSAPublicKey loadPublicKeyFromFile(String keyPath)
throws Exception {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(
keyPath)));
String line = null;
while ((line = br.readLine()) != null) {
if (line.charAt(0) == '-') {
continue;
} else {
sb.append(line);
sb.append('\r');
}
}
} finally {
if (br != null) {
br.close();
}
}
return loadPublicKey(sb.toString());
}
public static RSAPublicKey loadPublicKey(String publicKeyStr)
throws Exception {
Base64 decoder = new Base64();
byte[] buffer = decoder.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
public static void main(String[] args) throws Exception {
RSAPublicKey publicKey = loadPublicKeyFromFile("public_key.pem");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] rawText = CommonUtil.readFileContents("from.txt");
FileOutputStream out = null;
try {
out = new FileOutputStream("java_out.bin");
int BLOCK_SIZE = 128 - 11;
for (int i = 0; i < rawText.length; i += BLOCK_SIZE) {
int leftBytes = rawText.length - i;
int length = (leftBytes <= BLOCK_SIZE) ? leftBytes : BLOCK_SIZE;
out.write(cipher.doFinal(rawText, i, length));
}
} finally {
if (out != null) {
out.close();
}
}
}
}
======================IOS客户端公钥加密=======================
static SecKeyRef _public_key = nil;
- (SecKeyRef) getPublicKey{
if (_public_key == nil){
NSString* filePath = [[NSBundle mainBundle] pathForResource:@"public_key" ofType:@"der"];
NSData* certificateData = [NSData dataWithContentsOfFile:filePath];
SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);
if (myCertificate == nil) {
LErr(@"无法读取公钥内容");
return nil;
}
SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
SecTrustRef myTrust;
OSStatus status = (myCertificate,myPolicy,&myTrust);
SecTrustResultType trustResult;
if (status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult);
}else{
return nil;
}
_public_key = SecTrustCopyPublicKey(myTrust);
CFRelease(myCertificate);
CFRelease(myPolicy);
CFRelease(myTrust);
}
return _public_key;
}
- (NSData*) rsaEncrypt:(NSData*) data{
SecKeyRef key = [self getPublicKey];
if (key == nil) {
return nil;
}
size_t cipherBufferSize = SecKeyGetBlockSize(key);
uint8_t* cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
size_t blockSize = cipherBufferSize - 11;
size_t blockCount = (size_t)ceil([data length] / (double)blockSize);
NSMutableData *encryptedData = [[NSMutableData alloc] init];
for (int i=0; i
int bufferSize = (int)MIN(blockSize,[data length] - i * blockSize);
NSData *buffer = [data subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
OSStatus status = SecKeyEncrypt(key, kSecPaddingPKCS1, (const uint8_t *)[buffer bytes],
[buffer length], cipherBuffer, &cipherBufferSize);
if (status == noErr){
NSData *encryptedBytes = [[NSData alloc] initWithBytes:(const void *)cipherBuffer length:cipherBufferSize];
[encryptedData appendData:encryptedBytes];
}else{
if (cipherBuffer) free(cipherBuffer);
return nil;
}
}