zoukankan      html  css  js  c++  java
  • RSA加密解密

    X509 文件扩展名

    首先我们要理解文件的扩展名代表什么。DER、PEM、CRT和CER这些扩展名经常令人困惑。很多人错误地认为这些扩展名可以互相代替。尽管的确有时候有些扩展名是可以互换的,但是最好你能确定证书是如何编码的,进而正确地标识它们。正确地标识证书有助于证书的管理。

    编码 (也用于扩展名)

    • .DER = 扩展名DER用于二进制DER编码的证书。这些证书也可以用CER或者CRT作为扩展名。比较合适的说法是“我有一个DER编码的证书”,而不是“我有一个DER证书”。
    • .PEM = 扩展名PEM用于ASCII(Base64)编码的各种X.509 v3 证书文件开始由一行"—– BEGIN …“开始。

    常用的扩展名

    • .CRT = 扩展名CRT用于证书。证书可以是DER编码,也可以是PEM编码。扩展名CER和CRT几乎是同义词。这种情况在各种unix/linux系统中很常见。
    • CER = CRT证书的微软型式。可以用微软的工具把CRT文件转换为CER文件(CRT和CER必须是相同编码的,DER或者PEM)。扩展名为CER的文件可以被IE识别并作为命令调用微软的cryptoAPI(具体点就是rudll32.exe cryptext.dll, CyrptExtOpenCER),进而弹出一个对话框来导入并/或查看证书内容。
    • .KEY = 扩展名KEY用于PCSK#8的公钥和私钥。这些公钥和私钥可以是DER编码或者PEM编码。

    CRT文件和CER文件只有在使用相同编码的时候才可以安全地相互替代。

     
     
    RSA 特点:用私钥加密的字符串只能用公钥进行解密(记住私钥加密的字符串不能用私钥解密)
    RSA 特点:用公钥加密的字符串只能用私钥进行解密(记住公钥加密的字符串不能用公钥解密)
     
    p12格式:
    • 生成私钥文件
      $ openssl genrsa -out private.pem 1024

      • openssl:是一个自由的软件组织,专注做加密和解密的框架。
      • genrsa:指定了生成了算法使用RSA
      • -out:后面的参数表示生成的key的输入文件
      • 1024:表示的是生成key的长度,单位字节(bits)
    • 创建证书请求
      $ openssl req -new -key private.pem -out rsacert.csr

      • 可以拿着这个文件去数字证书颁发机构(即CA)申请一个数字证书。CA会给你一个新的文件cacert.pem,那才是你的数字证书。(要收费的)
    • 生成证书并签名,有效期10年
      $ openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt

      • 509是一种非常通用的证书格式。
      • 将用上面生成的密钥privkey.pem和rsacert.csr证书请求文件生成一个数字证书rsacert.crt。这个就是公钥
    • 转换格式 将 PEM 格式文件 转换成 DER 格式
      $ openssl x509 -outform der -in rsacert.crt -out rsacert.der

      • 在 iOS开发中,公钥是不能使用base64编码的,上面的命令是将公钥的base64编码字符串转换成二进制数据
    • 导出 P12 文件

      • 在iOS使用私钥不能直接使用,需要导出一个p12文件。下面命令就是将私钥文件导出为p12文件。

    $ openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt

    上面的证书iOS端使用p12和der;
     
    pem格式生成:
    MAC上生成公钥、私钥的方法,及使用
    • 1.打开终端,切换到自己想输出的文件夹下
    • 2.输入指令:openssl(openssl是生成各种秘钥的工具,mac已经嵌入
    • 3.输入指令:genrsa -out rsa_private_key.pem 1024 (生成私钥,java端使用的)
    • 4.输入指令:rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout (生成公钥)
    • 5.输入指令:pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt(私钥转格式,在ios端使用私钥解密时用这个私钥)
      注意:在MAC上生成三个.pem格式的文件,一个公钥,两个私钥,都可以在终端通过指令vim xxx.pem 打开,里面是字符串,第三步生成的私钥是java端用来解密数据的,第五步转换格式的私钥iOS端可以用来调试公钥、私钥解密(因为私钥不留在客户端)
    经过测试(iOS端):三个pem格式的密钥,
    1.其中rsa_private_key.pemrsa_public_key.pem在iOS中以文件形式加载加密解密时使用。
    2.其中pkcs8_rsa_private_key.pemrsa_public_key.pem在iOS中以字符串形式加载进行加密解密时使用
    也就是说在私钥在iOS端以字符串加载加密解密时所用的字符串必须进行pkcs8转码。
    我自己也是初步了解加密知识,测试的时候是这样,也不知道正确与否
     
    从网上找了一些加密方面的Demo,
    1.公钥、私钥字符串本地存在的参考:http://www.jianshu.com/p/8fd8306a95d0
    2.公钥、私钥文件形式存在本地参考:http://www.cnblogs.com/cocoajin/p/6183443.html
    (由于看的博客比较多,上面两个文档找了好久才再次找到)
    我把两个结合起来,写到一个工具类里面,可以选择性的根据文件和字符串秘钥进行加密解密:
    核心代码:
    .h代码:
     
    #import <Foundation/Foundation.h>
    
    @interface SecKeyTools : NSObject
    /**
     从x509 cer证书中读取公钥
     */
    + (SecKeyRef )publicKeyFromCer:(NSString *)cerFile;
    
    
    /**
     从 p12 文件中读取私钥,一般p12都有密码
     */
    + (SecKeyRef )privateKeyFromP12:(NSString *)p12File password:(NSString *)pwd;
    
    
    /**
     iOS 10 上可用如下接口SecKeyCreateWithData 从pem文件中读取私钥或公钥
     */
    + (SecKeyRef )publicKeyFromPem:(NSString *)pemFile keySize:(size_t )size;
    
    + (SecKeyRef )privaKeyFromPem:(NSString *)pemFile keySize:(size_t )size;
    /*
     使用公钥私钥字符串加密解密,注意:私钥字符串需要进行pkcs8转码
     */
    + (SecKeyRef)PublicKey:(NSString *)key;
    + (SecKeyRef)PrivateKey:(NSString *)key;
    @end

     
     
    .m代码:
     
    #import "SecKeyTools.h"
    
    @implementation SecKeyTools
    /**
     从x509 cer证书中读取公钥
     */
    + (SecKeyRef )publicKeyFromCer:(NSString *)cerFile
    {
        OSStatus            err;
        NSData *            certData;
        SecCertificateRef   cert;
        SecPolicyRef        policy;
        SecTrustRef         trust;
        SecTrustResultType  trustResult;
        SecKeyRef           publicKeyRef;
        
        certData = [NSData dataWithContentsOfFile:cerFile];
        cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData);
        policy = SecPolicyCreateBasicX509();
        err = SecTrustCreateWithCertificates(cert, policy, &trust);
        NSAssert(err==errSecSuccess,@"证书加载失败");
        err = SecTrustEvaluate(trust, &trustResult);
        NSAssert(err==errSecSuccess,@"公钥加载失败");
        publicKeyRef = SecTrustCopyPublicKey(trust);
        
        CFRelease(policy);
        CFRelease(cert);
        return publicKeyRef;
    }
    
    
    
    /**
     从 p12 文件中读取私钥,一般p12都有密码
     */
    + (SecKeyRef )privateKeyFromP12:(NSString *)p12File password:(NSString *)pwd
    
    {
        NSData *            pkcs12Data;
        CFArrayRef          imported;
        NSDictionary *      importedItem;
        SecIdentityRef      identity;
        OSStatus            err;
        SecKeyRef           privateKeyRef;
        
        pkcs12Data = [NSData dataWithContentsOfFile:p12File];
        err = SecPKCS12Import((__bridge CFDataRef)pkcs12Data,(__bridge CFDictionaryRef) @{(__bridge NSString *)kSecImportExportPassphrase:pwd}, &imported);
        NSAssert(err==errSecSuccess,@"p12加载失败");
        importedItem = (__bridge NSDictionary *) CFArrayGetValueAtIndex(imported, 0);
        identity = (__bridge SecIdentityRef) importedItem[(__bridge NSString *) kSecImportItemIdentity];
        
        err = SecIdentityCopyPrivateKey(identity, &privateKeyRef);
        NSAssert(err==errSecSuccess,@"私钥加载失败");
        CFRelease(imported);
        
        
        return privateKeyRef;
    }
    
    
    + (SecKeyRef )publicKeyFromPem:(NSString *)pemFile keySize:(size_t )size
    {
        SecKeyRef pubkeyref;
        NSError *readFErr = nil;
        CFErrorRef errref = noErr;
        NSString *pemStr = [NSString stringWithContentsOfFile:pemFile encoding:NSASCIIStringEncoding error:&readFErr];
        NSAssert(readFErr==nil, @"pem文件加载失败");
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"-----BEGIN PUBLIC KEY-----" withString:@""];
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"-----END PUBLIC KEY-----" withString:@""];
        NSData *dataPubKey = [[NSData alloc]initWithBase64EncodedString:pemStr options:0];
        
        NSMutableDictionary *dicPubkey = [[NSMutableDictionary alloc]initWithCapacity:1];
        [dicPubkey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [dicPubkey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)kSecAttrKeyClass];
        [dicPubkey setObject:@(size) forKey:(__bridge id)kSecAttrKeySizeInBits];
        
        pubkeyref = SecKeyCreateWithData((__bridge CFDataRef)dataPubKey, (__bridge CFDictionaryRef)dicPubkey, &errref);
        
        NSAssert(errref==noErr, @"公钥加载错误");
        
        return pubkeyref;
    }
    
    + (SecKeyRef )privaKeyFromPem:(NSString *)pemFile keySize:(size_t )size
    {
        SecKeyRef prikeyRef;
        NSError *readFErr = nil;
        CFErrorRef err = noErr;
        
        NSString *pemStr = [NSString stringWithContentsOfFile:pemFile encoding:NSASCIIStringEncoding error:&readFErr];
        NSAssert(readFErr==nil, @"pem文件加载失败");
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"-----BEGIN RSA PRIVATE KEY-----" withString:@""];
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        pemStr = [pemStr stringByReplacingOccurrencesOfString:@"-----END RSA PRIVATE KEY-----" withString:@""];
        NSData *pemData = [[NSData alloc]initWithBase64EncodedString:pemStr options:0];
        
        NSMutableDictionary *dicPrikey = [[NSMutableDictionary alloc]initWithCapacity:1];
        [dicPrikey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [dicPrikey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id)kSecAttrKeyClass];
        [dicPrikey setObject:@(size) forKey:(__bridge id)kSecAttrKeySizeInBits];
        
        prikeyRef = SecKeyCreateWithData((__bridge CFDataRef)pemData, (__bridge CFDictionaryRef)dicPrikey, &err);
        NSAssert(err==noErr, @"私钥加载错误");
        
        
        return prikeyRef;
    }
    + (SecKeyRef)PublicKey:(NSString *)key{
        NSRange spos = [key rangeOfString:@"-----BEGIN RSA PUBLIC KEY-----"];
        NSRange epos = [key rangeOfString:@"-----END RSA PUBLIC KEY-----"];
        if(spos.location != NSNotFound && epos.location != NSNotFound){
            NSUInteger s = spos.location + spos.length;
            NSUInteger e = epos.location;
            NSRange range = NSMakeRange(s, e-s);
            key = [key substringWithRange:range];
        }
        key = [key stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        key = [key stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        key = [key stringByReplacingOccurrencesOfString:@"	" withString:@""];
        key = [key stringByReplacingOccurrencesOfString:@" "  withString:@""];
    //    NSLog(@"key is ...%@
    ",key);
        // This will be base64 encoded, decode it.
        NSData *data = [[NSData alloc]initWithBase64EncodedString:key options:NSDataBase64DecodingIgnoreUnknownCharacters];
        data = [SecKeyTools stripPublicKeyHeader:data];
        if(!data){
            return nil;
        }
        
        //a tag to read/write keychain storage
        NSString *tag = @"RSAUtil_PubKey";
        NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
        
        // Delete any old lingering key with the same tag
        NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
        [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
        [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
        SecItemDelete((__bridge CFDictionaryRef)publicKey);
        
        // Add persistent version of the key to system keychain
        [publicKey setObject:data forKey:(__bridge id)kSecValueData];
        [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)
         kSecAttrKeyClass];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
         kSecReturnPersistentRef];
        
        CFTypeRef persistKey = nil;
        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
        if (persistKey != nil){
            CFRelease(persistKey);
        }
        if ((status != noErr) && (status != errSecDuplicateItem)) {
            return nil;
        }
        
        [publicKey removeObjectForKey:(__bridge id)kSecValueData];
        [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
        [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        
        // Now fetch the SecKeyRef version of the key
        SecKeyRef keyRef = nil;
        status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef);
        if(status != noErr){
            return nil;
        }
        return keyRef;
    }
    
    + (SecKeyRef)PrivateKey:(NSString *)key{
        NSRange spos = [key rangeOfString:@"-----BEGIN RSA PRIVATE KEY-----"];
        NSRange epos = [key rangeOfString:@"-----END RSA PRIVATE KEY-----"];
        if(spos.location != NSNotFound && epos.location != NSNotFound){
            NSUInteger s = spos.location + spos.length;
            NSUInteger e = epos.location;
            NSRange range = NSMakeRange(s, e-s);
            key = [key substringWithRange:range];
        }
        key = [key stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        key = [key stringByReplacingOccurrencesOfString:@"
    " withString:@""];
        key = [key stringByReplacingOccurrencesOfString:@"	" withString:@""];
        key = [key stringByReplacingOccurrencesOfString:@" "  withString:@""];
        
        // This will be base64 encoded, decode it.
        NSData *data = [[NSData alloc]initWithBase64EncodedString:key options:NSDataBase64DecodingIgnoreUnknownCharacters];
        data = [SecKeyTools stripPrivateKeyHeader:data];
        if(!data){
            return nil;
        }
        
        //a tag to read/write keychain storage
        NSString *tag = @"RSAUtil_PrivKey";
        NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
        
        // Delete any old lingering key with the same tag
        NSMutableDictionary *privateKey = [[NSMutableDictionary alloc] init];
        [privateKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
        [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [privateKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
        SecItemDelete((__bridge CFDictionaryRef)privateKey);
        
        // Add persistent version of the key to system keychain
        [privateKey setObject:data forKey:(__bridge id)kSecValueData];
        [privateKey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id)
         kSecAttrKeyClass];
        [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
         kSecReturnPersistentRef];
        
        CFTypeRef persistKey = nil;
        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey);
        if (persistKey != nil){
            CFRelease(persistKey);
        }
        if ((status != noErr) && (status != errSecDuplicateItem)) {
            return nil;
        }
        
        [privateKey removeObjectForKey:(__bridge id)kSecValueData];
        [privateKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
        [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
        [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        
        // Now fetch the SecKeyRef version of the key
        SecKeyRef keyRef = nil;
        status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef);
        if(status != noErr){
            return nil;
        }
        return keyRef;
    }
    + (NSData *)stripPublicKeyHeader:(NSData *)d_key{
        // Skip ASN.1 public key header
        if (d_key == nil) return(nil);
        
        unsigned long len = [d_key length];
        if (!len) return(nil);
        
        unsigned char *c_key = (unsigned char *)[d_key bytes];
        unsigned int  idx     = 0;
        
        if (c_key[idx++] != 0x30) return(nil);
        
        if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
        else idx++;
        
        // PKCS #1 rsaEncryption szOID_RSA_RSA
        static unsigned char seqiod[] =
        { 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
            0x01, 0x05, 0x00 };
        if (memcmp(&c_key[idx], seqiod, 15)) return(nil);
        
        idx += 15;
        
        if (c_key[idx++] != 0x03) return(nil);
        
        if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
        else idx++;
        
        if (c_key[idx++] != '') return(nil);
        
        // Now make a new NSData from this buffer
        return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
    }
    
    //credit: http://hg.mozilla.org/services/fx-home/file/tip/Sources/NetworkAndStorage/CryptoUtils.m#l1036
    + (NSData *)stripPrivateKeyHeader:(NSData *)d_key{
        // Skip ASN.1 private key header
        if (d_key == nil) return(nil);
        
        unsigned long len = [d_key length];
        if (!len) return(nil);
        
        unsigned char *c_key = (unsigned char *)[d_key bytes];
        unsigned int  idx     = 22; //magic byte at offset 22
        
        if (0x04 != c_key[idx++]) return nil;
        
        //calculate length of the key
        unsigned int c_len = c_key[idx++];
        int det = c_len & 0x80;
        if (!det) {
            c_len = c_len & 0x7f;
        } else {
            int byteCount = c_len & 0x7f;
            if (byteCount + idx > len) {
                //rsa length field longer than buffer
                return nil;
            }
            unsigned int accum = 0;
            unsigned char *ptr = &c_key[idx];
            idx += byteCount;
            while (byteCount) {
                accum = (accum << 8) + *ptr;
                ptr++;
                byteCount--;
            }
            c_len = accum;
        }
        
        // Now make a new NSData from this buffer
        return [d_key subdataWithRange:NSMakeRange(idx, c_len)];
    }
    @end
    对于加密还是一知半解,有写错的还望指正!!
     
  • 相关阅读:
    QSslError 类
    QNetworkRequest 请求类
    QFTP走了以后QNetworkAccessManager出现了
    Android之SQLite总结
    Android之Handler机制
    Android之SeekBar总结(一)
    Android之测试相关知识点
    Android数据储存之SharedPreferences总结
    android studio的常用快捷键
    BitmapFactory.Options详解
  • 原文地址:https://www.cnblogs.com/sunjianfei/p/6733448.html
Copyright © 2011-2022 走看看