IOS-加密

对称加密

  • 在1976年以前,所有的加密方法都是同一种模式:加密、解密使用同一种算法。在交互数据的时候,彼此通信的双方就必须将规则告诉对方,否则没法解密。那么加密和解密的规则(简称密钥),它保护就显得尤其重要。传递密钥就成为了最大的隐患。这种加密方式被成为对称加密算法(symmetric encryption algorithm)密钥就是 KEY

  • 1976年,两位美国计算机学家 迪菲(W.Diffie)、赫尔曼( M.Hellman ) 提出了一种崭新构思,可以在不直接传递密钥的情况下,完成密钥交换。这被称为“迪菲赫尔曼密钥交换”算法。开创了密码学研究的新方向

RSA 算法 – 不直接传递密钥的情况下 完成密钥交换。

  • 1977年三位麻省理工学院的数学家 罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起设计了一种算法,可以实现非对称加密。这个算法用他们三个人的名字命名,叫做RSA算法。

  • RSA数学原理

    • 上世纪70年代产生的一种加密算法。其加密方式比较特殊,需要两个密钥:公开密钥简称公钥(publickey)和私有密钥简称私钥(privatekey)。公钥加密,私钥解密;私钥加密,公钥解密。这个加密算法就是伟大的RSA

离散对数问题

  • 1.两个数互为质数 比如 3和17

image.png

  • 2.从图中可得 3从1次方到16次方 取模 17 是一个循环

image.png

  • 3.当3的N次方取模17为12时 我们是很难知道 N是多少的 只能一个个去检验。比如这个N可能是是13也可能是29…

欧拉函数

  • 关于互质关系
    • 如果两个正整数,除了1以外,没有其他公因数,我们就称这两个数是互质关系
  • 计算这个值的方式叫做欧拉函数,使用:Φ(n)表示
    • 如:
    • 计算8的欧拉函数,和8互质的 1、2、3、4、5、6、7、8
      • φ(8) = 4 分别为 1、3、5、7
    • 计算7的欧拉函数,和7互质的 1、2、3、4、5、6、7
      • φ(7) = 6 分别为 1、2、3、4、5、6
    • 计算56的欧拉函数
      • φ(56) = φ(8) * φ(7) = 4 * 6 = 24
  • 1.当n是质数的时候比如 7 φ(n) = n-1.
  • 2.如果n可以分解成两个互质的整数之积,如n=AB则:φ(AB)=φ(A)* φ(B)
    • 根据以上两点得到:
    • 如果N是两个质数P1 和 P2的乘积则
    • φ(N)=φ(P1)* φ(P2)=(P1-1)*(P2-1)

欧拉定理

  • 如果两个正整数m和n互质,那么m的φ(n)次方减去1,可以被n整除。

image.png
如:m = 5,n = 4 φ(4) = 2 5的2次方 25 取模 4 = 1
如:m = 7,n = 4 φ(4) = 2 7的2次方 49 取模 4 = 1

费马小定理

  • 欧拉定理的特殊情况:如果两个正整数m和n互质,而且n为质数!那么φ(n)结果就是n-1。
  • 就是n是质数 如 3、5、7 φ(n) = n-1

公式转换

image.png

  • 1.如:m=4,n=5 4的4次方 取模 5 恒等于 1
  • 2.K 是任意正整数 如:K=2 4的8次方 取模5 也是恒等于1
  • 3.这边我们简单一线k=1 就是 4的4+1 次方 等于 1024 取模 5 恒等于 4

模反元素

image.png

  • 如果两个正整数e和x互质,那么一定可以找到整数d使得ed-1 被x整除。 如e=3,x=4 ,可以找到 d = 3,d=3、d=7,那么d就是e对于x的模反元素。
  • 33 = 24+1 k = 2
  • 37 = 54+1 k = 5

第5条公式的转变可以理解为 当x = φ(n) 的时候

  • 我的理解 当 M 与 N 互质 我们等到 x = φ(n),这个时候我们再找到一个与 x, φ(n) 互质的 e
  • M = 4
  • N = 5 -> x = φ(5) = 4
  • e 与 4 互质 假如 e = 3 可以找到
  • d = 3 33 = 24 + 1
  • k = 2 ed = kx + 1 = kφ(n)+1 = 9
  • M的9次方取模5 等于 4
  • 思路其实就是 m和n 互质 等到 φ(n) 再找到与 φ(n) 互质的 e , e与φ(n) 相称的积m的 e*φ(n) 的次方 取模 N 恒等于 M .

最后得 M = 4,n = 5 ,e = 3 ,d=3 4的9次方取模5 等于4

加密解密

  • 假如私钥 是 e和n , 公钥就是 d和n
  • 我们通过私钥 e和n 加密 M 成为C 传递给 服务端后服务端公司公钥解密 最后还是 M。

image.png

image.png

终端练习

image.png

image.png

  • 生成一个私钥然后从私钥中提取公钥

image.png

  • 公钥加密私钥解密,私钥签名加密-公钥验证解密

image.png

通过私钥请求证书

openssl req -new -key private.pem -out rsacert.csr
复制代码
  • 输入国家CN
  • 省份 ZheJiang
  • 城市 HangZhou
  • 公司名 XXX
  • 地址 XXX@qq.com
  • 密码:可不填

image.png

证书认证

openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
复制代码

转换格式 crt->der

openssl x509 -outform der -in rsacert.crt -out rascert.der
复制代码

获取p12文件

openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
复制代码

base64 编码解码

vi message.txt
hello 
:wq
 - base编码
 base64 message.txt -o abc.txt
 - base解码
 base64 abc.txt -o 123.txt -D
复制代码
  • 代码练习base64加密解密
//64编码
-(NSString *)base64Endcode:(NSString *)string{
    NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding];
    
    return [data base64EncodedStringWithOptions:0];
}

-(NSString *)base64Decode:(NSString *)string{
    NSData * data = [[NSData alloc] initWithBase64EncodedString:string options:0];
    
    return  [[NSString alloc] initWithData:data encoding:(NSUTF8StringEncoding)];
}
复制代码
  • 代码练习RSA加密解密
    • 导入RSACryptor文件
//
//  RSACryptor.h
//  EncryptDemo
//
//  Created by H on 2018/10/16.
//  Copyright © 2018年 hank. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface RSACryptor : NSObject
    
+ (instancetype)sharedRSACryptor;
    
    /**
     *  生成密钥对
     *
     *  @param keySize 密钥尺寸,可选数值(512/1024/2048)
     */
- (void)generateKeyPair:(NSUInteger)keySize;
    
    /**
     *  加载公钥
     *
     *  @param publicKeyPath 公钥路径
     *
     @code
     # 生成证书
     $ openssl genrsa -out ca.key 1024
     # 创建证书请求
     $ openssl req -new -key ca.key -out rsacert.csr
     # 生成证书并签名
     $ openssl x509 -req -days 3650 -in rsacert.csr -signkey ca.key -out rsacert.crt
     # 转换格式
     $ openssl x509 -outform der -in rsacert.crt -out rsacert.der
     @endcode
     */
- (void)loadPublicKey:(NSString *)publicKeyPath;
    
    /**
     *  加载私钥
     *
     *  @param privateKeyPath p12文件路径
     *  @param password       p12文件密码
     *
     @code
     openssl pkcs12 -export -out p.p12 -inkey ca.key -in rsacert.crt
     @endcode
     */
- (void)loadPrivateKey:(NSString *)privateKeyPath password:(NSString *)password;
    
    /**
     *  加密数据
     *
     *  @param plainData 明文数据
     *
     *  @return 密文数据
     */
- (NSData *)encryptData:(NSData *)plainData;
    
    /**
     *  解密数据
     *
     *  @param cipherData 密文数据
     *
     *  @return 明文数据
     */
- (NSData *)decryptData:(NSData *)cipherData;
    
    @end

复制代码
#import "RSACryptor.h"

// 填充模式
#define kTypeOfWrapPadding        kSecPaddingPKCS1
//kSecPaddingNone  不填充! 密文每次都不会变化.

// 公钥/私钥标签
#define kPublicKeyTag            "com.logic.EncryptDemo.publickey"
#define kPrivateKeyTag            "com.logic.EncryptDemo.privatekey"

static const uint8_t publicKeyIdentifier[]        = kPublicKeyTag;
static const uint8_t privateKeyIdentifier[]        = kPrivateKeyTag;

@interface RSACryptor() {
    SecKeyRef publicKeyRef;                             // 公钥引用
    SecKeyRef privateKeyRef;                            // 私钥引用
}
    
    @property (nonatomic, retain) NSData *publicTag;        // 公钥标签
    @property (nonatomic, retain) NSData *privateTag;       // 私钥标签
    
    @end

@implementation RSACryptor
    
+ (instancetype)sharedRSACryptor {
    static id instance;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}
    
- (instancetype)init {
    self = [super init];
    if (self) {
        // 查询密钥的标签
        _privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
        _publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
    }
    return self;
}
    
#pragma mark - 加密 & 解密数据
- (NSData *)encryptData:(NSData *)plainData {
    OSStatus sanityCheck = noErr;
    size_t cipherBufferSize = 0;
    size_t keyBufferSize = 0;
    
    NSAssert(plainData != nil, @"明文数据为空");
    NSAssert(publicKeyRef != nil, @"公钥为空");
    
    NSData *cipher = nil;
    uint8_t *cipherBuffer = NULL;
    
    // 计算缓冲区大小
    cipherBufferSize = SecKeyGetBlockSize(publicKeyRef);
    keyBufferSize = [plainData length];
    
    if (kTypeOfWrapPadding == kSecPaddingNone) {
        NSAssert(keyBufferSize <= cipherBufferSize, @"加密内容太大");
    } else {
        NSAssert(keyBufferSize <= (cipherBufferSize - 11), @"加密内容太大");
    }
    
    // 分配缓冲区
    cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
    memset((void *)cipherBuffer, 0x0, cipherBufferSize);
    
    // 使用公钥加密
    sanityCheck = SecKeyEncrypt(publicKeyRef,
                                kTypeOfWrapPadding,
                                (const uint8_t *)[plainData bytes],
                                keyBufferSize,
                                cipherBuffer,
                                &cipherBufferSize
                                );
    
    NSAssert(sanityCheck == noErr, @"加密错误,OSStatus == %d", sanityCheck);
    
    // 生成密文数据
    cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize];
    
    if (cipherBuffer) free(cipherBuffer);
    
    return cipher;
}
    
- (NSData *)decryptData:(NSData *)cipherData {
    OSStatus sanityCheck = noErr;
    size_t cipherBufferSize = 0;
    size_t keyBufferSize = 0;
    
    NSData *key = nil;
    uint8_t *keyBuffer = NULL;
    
    SecKeyRef privateKey = NULL;
    
    privateKey = [self getPrivateKeyRef];
    NSAssert(privateKey != NULL, @"私钥不存在");
    
    // 计算缓冲区大小
    cipherBufferSize = SecKeyGetBlockSize(privateKey);
    keyBufferSize = [cipherData length];
    
    NSAssert(keyBufferSize <= cipherBufferSize, @"解密内容太大");
    
    // 分配缓冲区
    keyBuffer = malloc(keyBufferSize * sizeof(uint8_t));
    memset((void *)keyBuffer, 0x0, keyBufferSize);
    
    // 使用私钥解密
    sanityCheck = SecKeyDecrypt(privateKey,
                                kTypeOfWrapPadding,
                                (const uint8_t *)[cipherData bytes],
                                cipherBufferSize,
                                keyBuffer,
                                &keyBufferSize
                                );
    
    NSAssert1(sanityCheck == noErr, @"解密错误,OSStatus == %d", sanityCheck);
    
    // 生成明文数据
    key = [NSData dataWithBytes:(const void *)keyBuffer length:(NSUInteger)keyBufferSize];
    
    if (keyBuffer) free(keyBuffer);
    
    return key;
}
    
#pragma mark - 密钥处理
    /**
     *  生成密钥对
     */
- (void)generateKeyPair:(NSUInteger)keySize {
    OSStatus sanityCheck = noErr;
    publicKeyRef = NULL;
    privateKeyRef = NULL;
    
    NSAssert1((keySize == 512 || keySize == 1024 || keySize == 2048), @"密钥尺寸无效 %tu", keySize);
    
    // 删除当前密钥对
    [self deleteAsymmetricKeys];
    
    // 容器字典
    NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
    
    // 设置密钥对的顶级字典
    [keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits];
    
    // 设置私钥字典
    [privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
    [privateKeyAttr setObject:_privateTag forKey:(__bridge id)kSecAttrApplicationTag];
    
    // 设置公钥字典
    [publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
    [publicKeyAttr setObject:_publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    
    // 设置顶级字典属性
    [keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
    [keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
    
    // SecKeyGeneratePair 返回密钥对引用
    sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKeyRef, &privateKeyRef);
    NSAssert((sanityCheck == noErr && publicKeyRef != NULL && privateKeyRef != NULL), @"生成密钥对失败");
}
    
    /**
     *  加载公钥
     */
- (void)loadPublicKey:(NSString *)publicKeyPath {
    
    NSAssert(publicKeyPath.length != 0, @"公钥路径为空");
    
    // 删除当前公钥
    if (publicKeyRef) CFRelease(publicKeyRef);
    
    // 从一个 DER 表示的证书创建一个证书对象
    NSData *certificateData = [NSData dataWithContentsOfFile:publicKeyPath];
    SecCertificateRef certificateRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);
    NSAssert(certificateRef != NULL, @"公钥文件错误");
    
    // 返回一个默认 X509 策略的公钥对象,使用之后需要调用 CFRelease 释放
    SecPolicyRef policyRef = SecPolicyCreateBasicX509();
    // 包含信任管理信息的结构体
    SecTrustRef trustRef;
    
    // 基于证书和策略创建一个信任管理对象
    OSStatus status = SecTrustCreateWithCertificates(certificateRef, policyRef, &trustRef);
    NSAssert(status == errSecSuccess, @"创建信任管理对象失败");
    
    // 信任结果
    SecTrustResultType trustResult;
    // 评估指定证书和策略的信任管理是否有效
    status = SecTrustEvaluate(trustRef, &trustResult);
    NSAssert(status == errSecSuccess, @"信任评估失败");
    
    // 评估之后返回公钥子证书
    publicKeyRef = SecTrustCopyPublicKey(trustRef);
    NSAssert(publicKeyRef != NULL, @"公钥创建失败");
    
    if (certificateRef) CFRelease(certificateRef);
    if (policyRef) CFRelease(policyRef);
    if (trustRef) CFRelease(trustRef);
}
    
    /**
     *  加载私钥
     */
- (void)loadPrivateKey:(NSString *)privateKeyPath password:(NSString *)password {
    
    NSAssert(privateKeyPath.length != 0, @"私钥路径为空");
    
    // 删除当前私钥
    if (privateKeyRef) CFRelease(privateKeyRef);
    
    NSData *PKCS12Data = [NSData dataWithContentsOfFile:privateKeyPath];
    CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
    CFStringRef passwordRef = (__bridge CFStringRef)password;
    
    // 从 PKCS #12 证书中提取标示和证书
    SecIdentityRef myIdentity;
    SecTrustRef myTrust;
    const void *keys[] =   {kSecImportExportPassphrase};
    const void *values[] = {passwordRef};
    CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    
    // 返回 PKCS #12 格式数据中的标示和证书
    OSStatus status = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
    
    if (status == noErr) {
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
        myIdentity = (SecIdentityRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
        myTrust = (SecTrustRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
    }
    
    if (optionsDictionary) CFRelease(optionsDictionary);
    
    NSAssert(status == noErr, @"提取身份和信任失败");
    
    SecTrustResultType trustResult;
    // 评估指定证书和策略的信任管理是否有效
    status = SecTrustEvaluate(myTrust, &trustResult);
    NSAssert(status == errSecSuccess, @"信任评估失败");
    
    // 提取私钥
    status = SecIdentityCopyPrivateKey(myIdentity, &privateKeyRef);
    NSAssert(status == errSecSuccess, @"私钥创建失败");
}
    
    /**
     *  删除非对称密钥
     */
- (void)deleteAsymmetricKeys {
    OSStatus sanityCheck = noErr;
    NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];
    
    // 设置公钥查询字典
    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPublicKey setObject:_publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    
    // 设置私钥查询字典
    [queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPrivateKey setObject:_privateTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    
    // 删除私钥
    sanityCheck = SecItemDelete((__bridge CFDictionaryRef)queryPrivateKey);
    NSAssert1((sanityCheck == noErr || sanityCheck == errSecItemNotFound), @"删除私钥错误,OSStatus == %d", sanityCheck);
    
    // 删除公钥
    sanityCheck = SecItemDelete((__bridge CFDictionaryRef)queryPublicKey);
    NSAssert1((sanityCheck == noErr || sanityCheck == errSecItemNotFound), @"删除公钥错误,OSStatus == %d", sanityCheck);
    
    if (publicKeyRef) CFRelease(publicKeyRef);
    if (privateKeyRef) CFRelease(privateKeyRef);
}
    
    /**
     *  获得私钥引用
     */
- (SecKeyRef)getPrivateKeyRef {
    OSStatus sanityCheck = noErr;
    SecKeyRef privateKeyReference = NULL;
    
    if (privateKeyRef == NULL) {
        NSMutableDictionary * queryPrivateKey = [[NSMutableDictionary alloc] init];
        
        // 设置私钥查询字典
        [queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
        [queryPrivateKey setObject:_privateTag forKey:(__bridge id)kSecAttrApplicationTag];
        [queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
        
        // 获得密钥
        sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
        
        if (sanityCheck != noErr) {
            privateKeyReference = NULL;
        }
    } else {
        privateKeyReference = privateKeyRef;
    }
    
    return privateKeyReference;
}
    
    @end
复制代码
  • 导入刚刚生成的rsacer.der 文件和 p.p12文件

image.png

  • 加载公钥和私钥
    //1\加载公钥
    [[RSACryptor sharedRSACryptor] loadPublicKey:[[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil]];
    
    //2.加载私钥
    [[RSACryptor sharedRSACryptor] loadPrivateKey:[[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil] password:@"123456"];

复制代码
  • 加密解密
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    
    //加密
    NSData * result = [[RSACryptor sharedRSACryptor] encryptData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
    
  NSString * base64 =  [result base64EncodedStringWithOptions:0];
    NSLog(@"%@",base64);
    
    //解密
   NSData * jiemi = [[RSACryptor sharedRSACryptor] decryptData:result];
    NSLog(@"解密:%@",[[NSString alloc] initWithData:jiemi encoding:NSUTF8StringEncoding]);
}

复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享