java rsa证书 ios 支持吗
2017-04-05 · 百度知道合伙人官方认证企业
育知同创教育
1【专注:Python+人工智能|Java大数据|HTML5培训】 2【免费提供名师直播课堂、公开课及视频教程】 3【地址:北京市昌平区三旗百汇物美大卖场2层,微信公众号:yuzhitc】
向TA提问
关注
展开全部
了之前三个终端进行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 = SecTrustCreateWithCertificates(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;
}
}
我是在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 = SecTrustCreateWithCertificates(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;
}
}
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询