android、ios与服务器端php使用rsa加密解密通讯

转自: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

CRSA.m代码

#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

其中openssl api包,我们可以在第一步RSA密钥生成工具openssl的include文件夹中得到,完整代码包请点击这里下载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值