zoukankan      html  css  js  c++  java
  • iOS下使用SHA1WithRSA算法加签源码

    首先了解一下几个相关概念,以方便后面遇到的问题的解决:

    RSA算法:1977年由Ron Rivest、Adi Shamirh和LenAdleman发明的,RSA就是取自他们三个人的名字。算法基于一个数论:将两个大素数相乘非常容易,但要对这个乘积的结果进行因式分解却非常困难,因此可以把乘积公开作为公钥。该算法能够抵抗目前已知的所有密码攻击。RSA算法是一种非对称算法,算法需要一对密钥,使用其中一个加密,需要使用另外一个才能解密。我们在进行RSA加密通讯时,就把公钥放在客户端,私钥留在服务器。

     PEM:既然使用RSA需要一对密钥,那么我们当然是要先使用工具来生成这样一对密钥了。在linux、unix下,最简单方便的就是使用openssl命令行了。而DER、PEM就是生成的密钥可选择的两种文件格式。DER是Distinguished Encoding Rules的简称,是一种信息传输语法规则,在ITU X.690中定义的。在ios端,我们的公钥就是需要这样一种格式的,我们可以从Certificate, Key, and Trust Services Reference这篇文档的SecCertificateCreateWithData函数的data参数的说明中看到。而PEM格式是一种对DER进行封装的格式,他只是把der的内容进行了base64编码并加上了头尾说明。openssl命令行默认输出的都是PEM格式的文件,要能够在ios下使用,我们需要指定使用DER或者先生成PEM然后转换称DER。还有那些keystore,pkcs,p7b,p12后面介绍

    IOS客户端的加解密首先我们需要导入Security.framework,

    在ios中,我们主要关注四个函数

      • SecKeyEncrypt:使用公钥对数据进行加密
      • SecKeyDecrypt:使用私钥对数据进行解密
      • SecKeyRawVerify:使用公钥对数字签名和数据进行验证,以确认该数据的来源合法性。什么是数字签名,可以参考百度百科这篇文章?
      • SecKeyRawSign:使用私钥对数据进行摘要并生成数字签名

      RSA算法有2个作用一个是加密一个是加签。从这几个函数中,我们可以看到,我们第一种是使用公钥能在客户端:加密数据,以及服务器端用私钥解密。

       第二个就是用私钥在客户端加签,然后用公钥在服务器端用公钥验签。第一种完全是为了加密,第二种是为了放抵赖,就是为了防止别人模拟我们的客户端来攻击我们的服务器,导致瘫痪。

    1.RSA加密解密:
     (1)获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥 (2)加密 (3)解密
    2.RSA签名和验证
     (1)获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥 (2)获取待签名的Hash码 (3)获取签名的字符串 (4)验证

    3.公钥与私钥的理解:
     (1)私钥用来进行解密和签名,是给自己用的。
     (2)公钥由本人公开,用于加密和验证签名,是给别人用的。
       (3)当该用户发送文件时,用私钥签名,别人用他给的公钥验证签名,可以保证该信息是由他发送的。当该用户接受文件时,别人用他的公钥加密,他用私钥解密,可以保证该信息只能由他接收到。

    首先加入头文件

    #import <CommonCrypto/CommonDigest.h>  

    #import <CommonCrypto/CommonCryptor.h>

    #import <Security/Security.h>

    #import "NSData+Base64.h"

    #define kChosenDigestLength CC_SHA1_DIGEST_LENGTH  // SHA-1消息摘要的数据位数160位 

    - (NSData *)getHashBytes:(NSData *)plainText {  
        CC_SHA1_CTX ctx;  
        uint8_t * hashBytes = NULL;  
        NSData * hash = nil;  
          
        // Malloc a buffer to hold hash.  
        hashBytes = malloc( kChosenDigestLength * sizeof(uint8_t) );  
        memset((voidvoid *)hashBytes, 0x0, kChosenDigestLength);  
        // Initialize the context.  
        CC_SHA1_Init(&ctx);  
        // Perform the hash.  
        CC_SHA1_Update(&ctx, (voidvoid *)[plainText bytes], [plainText length]);  
        // Finalize the output.  
        CC_SHA1_Final(hashBytes, &ctx);  
          
        // Build up the SHA1 blob.  
        hash = [NSData dataWithBytes:(const voidvoid *)hashBytes length:(NSUInteger)kChosenDigestLength];  
        if (hashBytes) free(hashBytes);  
          
        return hash;  
    }
    -(NSString *)signTheDataSHA1WithRSA:(NSString *)plainText  
    {  
        uint8_t* signedBytes = NULL;  
        size_t signedBytesSize = 0;  
        OSStatus sanityCheck = noErr;  
        NSData* signedHash = nil;  
      
        NSString * path = [[NSBundle mainBundle]pathForResource:@"keystore" ofType:@"p12"];  
        NSData * data = [NSData dataWithContentsOfFile:path];  
        NSMutableDictionary * options = [[NSMutableDictionary alloc] init]; // Set the private key query dictionary.  
        [options setObject:@"你的p12文件的密码" forKey:(id)kSecImportExportPassphrase];  
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);  
        OSStatus securityError = SecPKCS12Import((CFDataRef) data, (CFDictionaryRef)options, &items);  
        if (securityError!=noErr) {  
            return nil ;  
        }  
        CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);  
        SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);   
        SecKeyRef privateKeyRef=nil;  
        SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);  
        signedBytesSize = SecKeyGetBlockSize(privateKeyRef);  
          
        NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];  
          
        signedBytes = malloc( signedBytesSize * sizeof(uint8_t) ); // Malloc a buffer to hold signature.  
        memset((voidvoid *)signedBytes, 0x0, signedBytesSize);  
          
        sanityCheck = SecKeyRawSign(privateKeyRef,  
                                    kSecPaddingPKCS1SHA1,  
                                    (const uint8_t *)[[self getHashBytes:plainTextBytes] bytes],  
                                    kChosenDigestLength,  
                                    (uint8_t *)signedBytes,  
                                    &signedBytesSize);     
          
        if (sanityCheck == noErr)  
        {  
            signedHash = [NSData dataWithBytes:(const voidvoid *)signedBytes length:(NSUInteger)signedBytesSize];  
        }  
        else  
        {  
            return nil;  
        }  
      
        if (signedBytes)  
        {  
            free(signedBytes);  
        }  
        NSString *signatureResult=[NSString stringWithFormat:@"%@",[signedHash base64EncodedString]];  
        return signatureResult;  
    } 
    -(SecKeyRef)getPublicKey{  
        NSString *certPath = [[NSBundle mainBundle] pathForResource:@"keystore" ofType:@"p7b"];  
        SecCertificateRef myCertificate = nil;  
        NSData *certificateData = [[NSData alloc] initWithContentsOfFile:certPath];  
        myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certificateData);  
        SecPolicyRef myPolicy = SecPolicyCreateBasicX509();  
        SecTrustRef myTrust;  
        OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);  
        SecTrustResultType trustResult;  
        if (status == noErr) {  
            status = SecTrustEvaluate(myTrust, &trustResult);  
        }  
        return SecTrustCopyPublicKey(myTrust);  
    }  
      
      
    -(NSString *)RSAEncrypotoTheData:(NSString *)plainText  
    {  
          
        SecKeyRef publicKey=nil;  
        publicKey=[self getPublicKey];  
        size_t cipherBufferSize = SecKeyGetBlockSize(publicKey);  
        uint8_t *cipherBuffer = NULL;   
          
        cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));  
        memset((voidvoid *)cipherBuffer, 0*0, cipherBufferSize);  
          
        NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];  
        int blockSize = cipherBufferSize-11;  // 这个地方比较重要是加密问组长度  
        int numBlock = (int)ceil([plainTextBytes length] / (double)blockSize);  
        NSMutableData *encryptedData = [[NSMutableData alloc] init];  
        for (int i=0; i<numBlock; i++) {  
            int bufferSize = MIN(blockSize,[plainTextBytes length]-i*blockSize);  
            NSData *buffer = [plainTextBytes subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];  
            OSStatus status = SecKeyEncrypt(publicKey,  
                                            kSecPaddingPKCS1,  
                                            (const uint8_t *)[buffer bytes],  
                                            [buffer length],   
                                            cipherBuffer,  
                                            &cipherBufferSize);  
            if (status == noErr)  
            {  
                NSData *encryptedBytes = [[[NSData alloc]  
                                           initWithBytes:(const voidvoid *)cipherBuffer  
                                           length:cipherBufferSize] autorelease];  
                [encryptedData appendData:encryptedBytes];  
            }  
            else  
            {  
                return nil;  
            }  
        }  
        if (cipherBuffer)  
        {  
            free(cipherBuffer);  
        }  
        NSString *encrypotoResult=[NSString stringWithFormat:@"%@",[encryptedData base64EncodedString]];  
        return encrypotoResult;  
    } 

    相关链接:

    iOS下使用SHA1WithRSA算法加签源码

    iOS中使用RSA对数据进行加密解密

    ios下使用RSA算法加密与java后台解密配合demo

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

     iOS下使用SHA1WithRSA算法加签源码

    RSA implementations in Objective C

  • 相关阅读:
    STM32 F4 DAC DMA Waveform Generator
    STM32 F4 General-purpose Timers for Periodic Interrupts
    Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
    Python第十三天 django 1.6 导入模板 定义数据模型 访问数据库 GET和POST方法 SimpleCMDB项目 urllib模块 urllib2模块 httplib模块 django和web服务器整合 wsgi模块 gunicorn模块
    查看SQL Server服务运行帐户和SQL Server的所有注册表项
    Pycharm使用技巧(转载)
    SQL Server 2014内存优化表的使用场景
    Python第十天 print >> f,和fd.write()的区别 stdout的buffer 标准输入 标准输出 从控制台重定向到文件 标准错误 重定向 输出流和输入流 捕获sys.exit()调用 optparse argparse
    Python第七天 函数 函数参数 函数里的变量 函数返回值 多类型传值 函数递归调用 匿名函数 内置函数
    Python第六天 类型转换
  • 原文地址:https://www.cnblogs.com/On1Key/p/5458835.html
Copyright © 2011-2022 走看看