zoukankan      html  css  js  c++  java
  • java&Ios rsa 进行加密解密

    最近公司要准备做一个传输数据加密准备用RSA 首先说一下自己开发中越到到坑

    开始后台做给了我字符串格式的公钥、私钥做调试

    后台自己加密、解密、加签、验签,都没有问题, 我这边同样也是加密、解密、加签、验签都没有问题

    加密每次都是不同的,但是加签只要铭文固定,结果是一样 问题出在,同样的铭文,前端和后台加签出来不结果

    最后和后台讨论用我们前端生成的文件进行加密解密

    一、首先说一下生成公钥、私钥、证书的过程

    openssl genrsa -out private_key.pem 1024
    
    openssl req -new -key private_key.pem -out rsaCertReq.csr
    
    openssl x509 -req -days 3650 -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代码提现
    先请你把 public_key.der 和 private_key.p12  拖进你的Xcode项目里去 , 也请引入 Security.framework 以及 NSData+Base64.h/m 到项目里。
    NSData+Base64.h/m下载链接

    RSAEncryptor.h:
    #import <Foundation/Foundation.h>
    
    @interface RSAEncryptor : NSObject
    #pragma mark - Instance Methods -(void) loadPublicKeyFromFile: (NSString*) derFilePath; -(void) loadPublicKeyFromData: (NSData*) derData; -(void) loadPrivateKeyFromFile: (NSString*) p12FilePath password:(NSString*)p12Password; -(void) loadPrivateKeyFromData: (NSData*) p12Data password:(NSString*)p12Password; -(NSString*) rsaEncryptString:(NSString*)string; -(NSData*) rsaEncryptData:(NSData*)data ; -(NSString*) rsaDecryptString:(NSString*)string; -(NSData*) rsaDecryptData:(NSData*)data;
    #pragma mark - Class Methods
    +(void) setSharedInstance: (RSAEncryptor*)instance; +(RSAEncryptor*) sharedInstance;
    @end


    RSAEncryptor.m:
    #import "RSAEncryptor.h"

    #import <Security/Security.h>
    #import "NSData+Base64.h"


    @implementation RSAEncryptor
    {
        SecKeyRef publicKey;
        
        SecKeyRef privateKey;
    }


    -(void)dealloc
    {
        CFRelease(publicKey);
        CFRelease(privateKey);
    }



    -(SecKeyRef) getPublicKey {
        return publicKey;
    }

    -(SecKeyRef) getPrivateKey {
        return privateKey;
    }



    -(void) loadPublicKeyFromFile: (NSString*) derFilePath
    {
        NSData *derData = [[NSData alloc] initWithContentsOfFile:derFilePath];
        [self loadPublicKeyFromData: derData];
    }
    -(void) loadPublicKeyFromData: (NSData*) derData
    {
        publicKey = [self getPublicKeyRefrenceFromeData: derData];
    }

    -(void) loadPrivateKeyFromFile: (NSString*) p12FilePath password:(NSString*)p12Password
    {
        NSData *p12Data = [NSData dataWithContentsOfFile:p12FilePath];
        [self loadPrivateKeyFromData: p12Data password:p12Password];
    }

    -(void) loadPrivateKeyFromData: (NSData*) p12Data password:(NSString*)p12Password
    {
        privateKey = [self getPrivateKeyRefrenceFromData: p12Data password: p12Password];
    }




    #pragma mark - Private Methods

    -(SecKeyRef) getPublicKeyRefrenceFromeData: (NSData*)derData
    {
        SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)derData);
        SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
        SecTrustRef myTrust;
        OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
        SecTrustResultType trustResult;
        if (status == noErr) {
            status = SecTrustEvaluate(myTrust, &trustResult);
        }
        SecKeyRef securityKey = SecTrustCopyPublicKey(myTrust);
        CFRelease(myCertificate);
        CFRelease(myPolicy);
        CFRelease(myTrust);
        
        return securityKey;
    }


    -(SecKeyRef) getPrivateKeyRefrenceFromData: (NSData*)p12Data password:(NSString*)password
    {
        SecKeyRef privateKeyRef = NULL;
        NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
        [options setObject: password forKey:(__bridge id)kSecImportExportPassphrase];
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
        OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items);
        if (securityError == noErr && CFArrayGetCount(items) > 0) {
            CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
            SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
            securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
            if (securityError != noErr) {
                privateKeyRef = NULL;
            }
        }
        CFRelease(items);
        
        return privateKeyRef;
    }



    #pragma mark - Encrypt

    -(NSString*) rsaEncryptString:(NSString*)string {
        NSData* data = [string dataUsingEncoding:NSUTF8StringEncoding];
        NSData* encryptedData = [self rsaEncryptData: data];
        NSString* base64EncryptedString = [encryptedData base64EncodedString];
        return base64EncryptedString;
    }

    // 加密的大小受限于SecKeyEncrypt函数,SecKeyEncrypt要求明文和密钥的长度一致,如果要加密更长的内容,需要把内容按密钥长度分成多份,然后多次调用SecKeyEncrypt来实现
    -(NSData*) rsaEncryptData:(NSData*)data {
        SecKeyRef key = [self getPublicKey];
        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<blockCount; i++) {
            int bufferSize = 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;
            }
        }
        if (cipherBuffer){
            free(cipherBuffer);
        }
        return encryptedData;
    }




    #pragma mark - Decrypt

    -(NSString*) rsaDecryptString:(NSString*)string {
        NSData* data = [NSData dataFromBase64String: string];
        NSData* decryptData = [self rsaDecryptData: data];
        NSString* result = [[NSString alloc] initWithData: decryptData encoding:NSUTF8StringEncoding];
        return result;
    }

    -(NSData*) rsaDecryptData:(NSData*)data {
        SecKeyRef key = [self getPrivateKey];
        size_t cipherLen = [data length];
        void *cipher = malloc(cipherLen);
        [data getBytes:cipher length:cipherLen];
        size_t plainLen = SecKeyGetBlockSize(key) - 12;
        void *plain = malloc(plainLen);
        OSStatus status = SecKeyDecrypt(key, kSecPaddingPKCS1, cipher, cipherLen, plain, &plainLen);
        
        if (status != noErr) {
            return nil;
        }
        
        NSData *decryptedData = [[NSData alloc] initWithBytes:(const void *)plain length:plainLen];
        
        return decryptedData;
    }








    #pragma mark - Class Methods

    static RSAEncryptor* sharedInstance = nil;

    +(void) setSharedInstance: (RSAEncryptor*)instance
    {
        sharedInstance = instance;
    }

    +(RSAEncryptor*) sharedInstance
    {
        return sharedInstance;
    }


    好了,现在可以进行加密解密了

    在你需要的地方把以下代码粘贴进去验证

            RSAEncryptor* rsaEncryptor = [[RSAEncryptor alloc] init];
            NSString* publicKeyPath = [[NSBundle mainBundle] pathForResource:@"public_key" ofType:@"der"];
            NSString* privateKeyPath = [[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"p12"];
            [rsaEncryptor loadPublicKeyFromFile: publicKeyPath];
            [rsaEncryptor loadPrivateKeyFromFile: privateKeyPath password:@"ISAACS"];    // 这里,请换成你生成p12时的密码
            
            NSString* restrinBASE64STRING = [rsaEncryptor rsaEncryptString:@"I.O.S"];
            NSLog(@"Encrypted: %@", restrinBASE64STRING);       // 请把这段字符串Copy到JAVA这边main()里做测试
            NSString* decryptString = [rsaEncryptor rsaDecryptString: restrinBASE64STRING];
            NSLog(@"Decrypted: %@", decryptString);

    注意:

      代码里注意请把密码修改换成你的p12密码。

    三、JAVA 代码:

    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/Isaacs/Desktop/RSA_KEYS/rsa_public_key.pem";        // replace your public key path here
            String publicKeyPath =  "/Users/Isaacs/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(" Encrypt: " + testRSAEnWith64);
                System.out.println(" Decrypt: " + testRSADeWith64);
                
                // NSLog the encrypt string from Xcode , and paste it here.
                // 请粘贴来自IOS端加密后的字符串
    //            String rsaBase46StringFromIOS =
    //                    "nIIV7fVsHe8QquUbciMYbbumoMtbBuLsCr2yMB/WAhm+S/kGRPlf+k2GH8imZIYQ" + " " +
    //                    "QBDssVLQmS392QlxS87hnwMRJIzWw6vdRv/k79TgTfu6tI/9QTqIOvNlQIqtIcVm" + " " +
    //                    "R/suvydoymKgdlB+ce5/tHSxfqEOLLrL1Zl2PqJSP4A=";
    //            
    //            String decryptStringFromIOS = rsaEncryptor.decryptWithBase64(rsaBase46StringFromIOS);
    //            System.out.println("Decrypt result from ios client: " + 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(" ");
            }
            
            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(' ');  
                    }  
                }  
                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(' ');  
                    }  
                }  
                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();  
        }  


    现在可用你加密后的密文,发给后太让他解密,(同样后台进行加密,发给你进行解密)

  • 相关阅读:
    OSPF
    【今日CS 视觉论文速览】 24 Jan 2019
    【今日CS 视觉论文速览】Wed, 23 Jan 2019
    【今日CS 视觉论文速览】 21 Jan 2019
    【Processing学习笔记】安装与入门
    【今日CS 视觉论文速览】Part2, 18 Jan 2019
    【今日CS 视觉论文速览】Fri, 18 Jan 2019
    【今日CS 视觉论文速览】Thu, 17 Jan 2019
    【今日CS 视觉论文速览】Part2, 16 Jan 2019
    【今日CS 视觉论文速览】Wed, 16 Jan 2019
  • 原文地址:https://www.cnblogs.com/yangxiaolong/p/5526765.html
Copyright © 2011-2022 走看看