转自:http://blog.csdn.net/lx923988898/article/details/10374145
下载RSA密钥生成工具openssl,点击下载,解压缩至独立的文件夹,进入其中的bin目录,执行以下命令:
1
2
3
4
5
|
openssl genrsa -out rsa_private_key.pem 1024
openssl pkcs8 -topk8 -inform PEM -
in
rsa_private_key.pem -outform PEM -nocrypt -out private_key.pem
openssl rsa -
in
rsa_private_key.pem -pubout -out rsa_public_key.pem
|
第一条命令生成原始 RSA私钥文件 rsa_private_key.pem,第二条命令将原始 RSA私钥转换为 pkcs8格式,第三条生成RSA公钥 rsa_public_key.pem
从上面看出通过私钥能生成对应的公钥,因此我们将私钥private_key.pem用在服务器端,公钥发放给android跟ios等前端
第二步,php服务器端,使用openssl方法来进行加密解密类,代码如下:
<?php
/**
* @author alun (http://alunblog.duapp.com)
* @version 1.0
* @created 2013-5-17
*/
class
Rsa
{
private
static
$PRIVATE_KEY
= '-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAM9nUm7rPNhSgvsd
jMuCd5E7IMJB/80A1YY7jYV9fBCKdhVKmqea26QYuw6FW7B00fppEUTSazduSmn9
Yvhx9UOCcI75b0nq9FWm5O4P+Kp8l31M1pwsJ3cm+DceGOrFsl47vh9idiqj+abI
lJ4sTmJmDghmbks9YFlZSndQsIBlAgMBAAECgYAasa6vbgF3yi7niScc7l7bR2Pw
/LOivA+/ZhzR6JO2QUvvc5myJsFMPo6c0Nc7P93iv/EkDX0VNlHHkIBTf79URHXM
gXwMad4pHAeOiqxk5A9w/szDCBoETngtoqQGJq+QINxwPVvDEO4i224Uj3MKg2fo
4SDy3P1GCAAj1ahNoQJBAP4FV9vLWdLOOwOLnBpXt6vru4HT5VIf9fCeBIemuQ4C
/yRtgU38zXWgZ8AAmS6EjBEUDnN/tWid6UBKfgPDwAkCQQDRBP+Y9wIYIaSxeL7B
nHhPT25yAJCGK+l6r2qeaHVQr81O9YjusEi8E2M5OxCRolKxC3L7hrLJX8z1oyOV
dNx9AkBqYGhzpgv+qNiz2mJL8dH8ECMc8lTFeJbw5eu1tw8mHAEnCyisNSMBkGQC
Vv3PKjjR6hlHKwMYRZDpmIh/IRmpAkEAr1soLGaeZSxkhVetgbUJ4k/bct0yYr4Y
ZQshwcAVHBpBforT1JwkiVUim3MIFYY/JbVbQ9XfzL4Ir9OsGMkv6QJAPaQnyNY5
/D0PhXqODOM6jtAHHRfaSi4gve6AZ0iRz6YlB8beJ1ywZaJZWD9Cuw3zy4dDpCOn
A4tBsIdpMMoT+w==
-----
END
PRIVATE KEY-----';
/**
*返回对应的私钥
*/
private
static
function
getPrivateKey(){
$privKey
= self::
$PRIVATE_KEY
;
return
openssl_pkey_get_private(
$privKey
);
}
/**
* 私钥加密
*/
public
static
function
privEncrypt(
$data
)
{
if
(!
is_string
(
$data
)){
return
null;
}
return
openssl_private_encrypt(
$data
,
$encrypted
,self::getPrivateKey())?
base64_encode
(
$encrypted
) : null;
}
/**
* 私钥解密
*/
public
static
function
privDecrypt(
$encrypted
)
{
if
(!
is_string
(
$encrypted
)){
return
null;
}
return
(openssl_private_decrypt(
base64_decode
(
$encrypted
),
$decrypted
, self::getPrivateKey()))?
$decrypted
: null;
}
}
?>
打开private_key.pem,将上面的$PRIVATE_KEY,替换成private_key.pem的内容即可,服务器端我们只需要使用私钥来加密解密。
第三步,android前端,使用java的Cipher类来实现加密解密类,代码如下:
import
java.io.ByteArrayInputStream;
import
java.io.ByteArrayOutputStream;
import
java.io.InputStream;
import
java.security.KeyFactory;
import
java.security.NoSuchAlgorithmException;
import
java.security.PublicKey;
import
java.security.spec.X509EncodedKeySpec;
import
javax.crypto.Cipher;
import
android.util.Base64;
/**
* @author alun (http://alunblog.duapp.com)
* @version 1.0
* @created 2013-5-17
*/
public
class
Rsa {
private
static
final
String RSA_PUBLICE =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPZ1Ju6zzYUoL7HYzLgneROyDC"
+
"\r"
+
"Qf/NANWGO42FfXwQinYVSpqnmtukGLsOhVuwdNH6aRFE0ms3bkpp/WL4cfVDgnCO"
+
"\r"
+
"+W9J6vRVpuTuD/iqfJd9TNacLCd3Jvg3HhjqxbJeO74fYnYqo/mmyJSeLE5iZg4I"
+
"\r"
+
"Zm5LPWBZWUp3ULCAZQIDAQAB"
;
private
static
final
String ALGORITHM =
"RSA"
;
/**
* 得到公钥
* @param algorithm
* @param bysKey
* @return
*/
private
static
PublicKey getPublicKeyFromX509(String algorithm,
String bysKey)
throws
NoSuchAlgorithmException, Exception {
byte
[] decodedKey = Base64.decode(bysKey,Base64.DEFAULT);
X509EncodedKeySpec x509 =
new
X509EncodedKeySpec(decodedKey);
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
return
keyFactory.generatePublic(x509);
}
/**
* 使用公钥加密
* @param content
* @param key
* @return
*/
public
static
String encryptByPublic(String content) {
try
{
PublicKey pubkey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLICE);
Cipher cipher = Cipher.getInstance(
"RSA/ECB/PKCS1Padding"
);
cipher.init(Cipher.ENCRYPT_MODE, pubkey);
byte
plaintext[] = content.getBytes(
"UTF-8"
);
byte
[] output = cipher.doFinal(plaintext);
String s =
new
String(Base64.encode(output,Base64.DEFAULT));
return
s;
}
catch
(Exception e) {
return
null
;
}
}
/**
* 使用公钥解密
* @param content 密文
* @param key 商户私钥
* @return 解密后的字符串
*/
public
static
String decryptByPublic(String content) {
try
{
PublicKey pubkey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLICE);
Cipher cipher = Cipher.getInstance(
"RSA/ECB/PKCS1Padding"
);
cipher.init(Cipher.DECRYPT_MODE, pubkey);
InputStream ins =
new
ByteArrayInputStream(Base64.decode(content,Base64.DEFAULT));
ByteArrayOutputStream writer =
new
ByteArrayOutputStream();
byte
[] buf =
new
byte
[
128
];
int
bufl;
while
((bufl = ins.read(buf)) != -
1
) {
byte
[] block =
null
;
if
(buf.length == bufl) {
block = buf;
}
else
{
block =
new
byte
[bufl];
for
(
int
i =
0
; i < bufl; i++) {
block[i] = buf[i];
}
}
writer.write(cipher.doFinal(block));
}
return
new
String(writer.toByteArray(),
"utf-8"
);
}
catch
(Exception e) {
return
null
;
}
}
}
需要注意的是,在初始化Cipher对象时,一定要指明使用"RSA/ECB/PKCS1Padding"格式如Cipher.getInstance("RSA/ECB/PKCS1Padding");
打开rsa_public_key.pem文件,将上面代码的RSA_PUBLICE替换成其中内容即可。
第四步,ios前端,iOS上没有直接处理RSA加密的API,网上说的大多数也是处理X.509的证书的方法来实现,不过X.509证书是带签名的,在php端openssl_pkey_get_private方法获取密钥时,第二个参数需要传签名,而android端实现X.509证书加密解密较为不易,在这里我们利用ios兼容c程序的特点,利用openssl的api实现rsa的加密解密,代码如下:
CRSA.h代码:
#import <Foundation/Foundation.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
typedef
enum
{
KeyTypePublic,
KeyTypePrivate
}KeyType;
typedef
enum
{
RSA_PADDING_TYPE_NONE = RSA_NO_PADDING,
RSA_PADDING_TYPE_PKCS1 = RSA_PKCS1_PADDING,
RSA_PADDING_TYPE_SSLV23 = RSA_SSLV23_PADDING
}RSA_PADDING_TYPE;
@interface CRSA : NSObject{
RSA *_rsa;
}
+ (id)shareInstance;
- (
BOOL
)importRSAKeyWithType:(KeyType)type;
- (
int
)getBlockSizeWithRSA_PADDING_TYPE:(RSA_PADDING_TYPE)padding_type;
- (NSString *) encryptByRsa:(NSString*)content withKeyType:(KeyType)keyType;
- (NSString *) decryptByRsa:(NSString*)content withKeyType:(KeyType)keyType;
@end
#import "CRSA.h"
#define BUFFSIZE 1024
#import "Base64.h"
#define PADDING RSA_PADDING_TYPE_PKCS1
@implementation CRSA
+ (id)shareInstance
{
static
CRSA *_crsa = nil;
static
dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_crsa = [[self alloc] init];
});
return
_crsa;
}
- (
BOOL
)importRSAKeyWithType:(KeyType)type
{
FILE
*file;
NSString *keyName = type == KeyTypePublic ? @
"public_key"
: @
"private_key"
;
NSString *keyPath = [[NSBundle mainBundle] pathForResource:keyName ofType:@
"pem"
];
file =
fopen
([keyPath UTF8String],
"rb"
);
if
(NULL != file)
{
if
(type == KeyTypePublic)
{
_rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL);
assert
(_rsa != NULL);
}
else
{
_rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
assert
(_rsa != NULL);
}
fclose
(file);
return
(_rsa != NULL) ? YES : NO;
}
return
NO;
}
- (NSString *) encryptByRsa:(NSString*)content withKeyType:(KeyType)keyType
{
if
(![self importRSAKeyWithType:keyType])
return
nil;
int
status;
int
length = [content length];
unsigned
char
input[length + 1];
bzero(input, length + 1);
int
i = 0;
for
(; i < length; i++)
{
input[i] = [content characterAtIndex:i];
}
NSInteger flen = [self getBlockSizeWithRSA_PADDING_TYPE:PADDING];
char
*encData = (
char
*)
malloc
(flen);
bzero(encData, flen);
switch
(keyType) {
case
KeyTypePublic:
status = RSA_public_encrypt(length, (unsigned
char
*)input, (unsigned
char
*)encData, _rsa, PADDING);
break
;
default
:
status = RSA_private_encrypt(length, (unsigned
char
*)input, (unsigned
char
*)encData, _rsa, PADDING);
break
;
}
if
(status)
{
NSData *returnData = [NSData dataWithBytes:encData length:status];
free
(encData);
encData = NULL;
NSString *ret = [returnData base64EncodedString];
return
ret;
}
free
(encData);
encData = NULL;
return
nil;
}
- (NSString *) decryptByRsa:(NSString*)content withKeyType:(KeyType)keyType
{
if
(![self importRSAKeyWithType:keyType])
return
nil;
int
status;
NSData *data = [content base64DecodedData];
int
length = [data length];
NSInteger flen = [self getBlockSizeWithRSA_PADDING_TYPE:PADDING];
char
*decData = (
char
*)
malloc
(flen);
bzero(decData, flen);
switch
(keyType) {
case
KeyTypePublic:
status = RSA_public_decrypt(length, (unsigned
char
*)[data bytes], (unsigned
char
*)decData, _rsa, PADDING);
break
;
default
:
status = RSA_private_decrypt(length, (unsigned
char
*)[data bytes], (unsigned
char
*)decData, _rsa, PADDING);
break
;
}
if
(status)
{
NSMutableString *decryptString = [[NSMutableString alloc] initWithBytes:decData length:
strlen
(decData) encoding:NSASCIIStringEncoding];
free
(decData);
decData = NULL;
return
decryptString;
}
free
(decData);
decData = NULL;
return
nil;
}
- (
int
)getBlockSizeWithRSA_PADDING_TYPE:(RSA_PADDING_TYPE)padding_type
{
int
len = RSA_size(_rsa);
if
(padding_type == RSA_PADDING_TYPE_PKCS1 || padding_type == RSA_PADDING_TYPE_SSLV23) {
len -= 11;
}
return
len;
}
@end