iOS逆向 06:RSA加密(下)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: iOS逆向 06:RSA加密(下)

本文主要介绍RSA的代码演示过程


RSA代码演示


前提:准备好公钥、私钥,需要在终端生成(属于自己签名)


证书申请步骤


  • 1、申请CSR文件:keychain -> 证书助理 -> 从证书颁发机构请求证书
  • 2、生成CSR请求文件(证书颁发机构信息 + 公钥)


  • 命令:openssl req -new -key private.pem -out rsacert.csr

image.png

  • 3、生成CRT证书(自己签名,没有认证的)
  • 命令:openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
  • 4、生成der文件
  • 命令:openssl x509 -outform der -in rsacert.crt -out rsacert.der

image.png

5、获取p12文件

  • 命令:openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt

    image.png
  • 注:代码中使用der格式


base64编码


base64编码由0-9、a-z、A-Z + /(64个字符 )加上 =(表示补零) 来组成的文本


终端命令


  • vi message.txt
  • base64编码:base64 message.txt -o abc.txt
  • base64解码:base abc.txt -o 123.txt -D


代码演示


- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"en:%@", [self base64Encode:@"A"]);
    NSLog(@"de:%@", [self base64Decode:@"QQ=="]);
}
//编码
- (NSString *)base64Encode:(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];
}
<!--打印结果-->
en:QQ==
de:A

base64说明


  • 1、base64只适用于表示二进制文件
  • 2、base64编码后,文件数量变多,不适合对大型数据进行编码
  • 3、bse64和数据是一一对应


代码演示


前提:通过证书申请步骤,准备好p12和der文件


  • 1、创建RSA加解密类:RSACryptor
<!--RSACryptor.h-->
#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
<!--RSACryptor.m-->
#import "RSACryptor.h"
// 填充模式
/*
 - kSecPaddingNone 不填充
 - kSecPaddingPKCS1 填充
 */
#define kTypeOfWrapPadding        kSecPaddingPKCS1
// 公钥/私钥标签
#define kPublicKeyTag            "com.cjl.EncryptDemo.publickey"
#define kPrivateKeyTag            "com.cjl.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
  • 2、通过代码加载公钥(der文件)和私钥(p12文件)
- (void)testRSA{
    //1、加载公钥
    [[RSACryptor sharedRSACryptor] loadPublicKey:[[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil]];
    //2、加载私钥
    [[RSACryptor sharedRSACryptor] loadPrivateKey:[[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil] password:@"123456"];
}
  • 3、使用RSA进行加解密
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //加密
    NSData *result = [[RSACryptor sharedRSACryptor] encryptData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
    NSString *base64 = [result base64EncodedStringWithOptions:0];
    NSLog(@"en - %@", base64);
    //解密
    NSData *jiemi = [[RSACryptor sharedRSACryptor] decryptData:result];
    NSLog(@"de - %@", [[NSString alloc] initWithData:jiemi encoding:NSUTF8StringEncoding]);
}
<!--打印结果-->
en - L+1uUQ9eSzZmVJuEXMZ7Z8Wr241ze/6XbKMoBTLDdCvlf2bLcJPDJor5RVvn00rPg65NLwd3AyZDy+4/3t41bAJtHo2+MjmAHJ32rmTTx/HH5B3WOghOGqhLZS1hLFt62tic8betewTgzJg9IvMbtSvXDl4XdgLXM8ZWFdosneg=
de - hello

从结果中可以发现,每次RSA加密结果不一样,原因是因为RSA有个填充模式,导致每次结果不一样


  • kSecPaddingNone 不填充,密文每次不变
  • kSecPaddingPKCS1 填充,密文随机变化

image.png


总结


  • base64编码说明:


  • 1、base64只适用于表示二进制文件
  • 2、base64编码后,文件数量变多,不适合对大型数据进行编码
  • 3、bse64和数据是一一对应


  • RSA代码加解密是通过Security框架


  • 加密:使用SecKeyEncrypt函数
  • 解密:使用SecKeyDecrypt函数
  • 加密有两种填充模式:
  • kSecPaddingNone 不填充,密文每次不变
  • kSecPaddingPKCS1 填充,密文每次随机变化


相关文章
|
2月前
|
安全 算法 网络安全
浅谈非对称加密(RSA)
浅谈非对称加密(RSA)
|
1月前
|
算法 安全 Go
RSA加密算法详解与Python和Go实现
RSA加密算法详解与Python和Go实现
94 1
|
1月前
|
算法 安全 网络安全
使用 Python 实现 RSA 加密
使用 Python 实现 RSA 加密
53 2
|
2月前
|
存储 安全 算法
RSA在手,安全我有!Python加密解密技术,让你的数据密码坚不可摧
【9月更文挑战第11天】在数字化时代,信息安全至关重要。传统的加密方法已难以应对日益复杂的网络攻击。RSA加密算法凭借其强大的安全性和广泛的应用场景,成为保护敏感数据的首选。本文介绍RSA的基本原理及在Python中的实现方法,并探讨其优势与挑战。通过使用PyCryptodome库,我们展示了RSA加密解密的完整流程,帮助读者理解如何利用RSA为数据提供安全保障。
122 5
|
2月前
|
安全 算法 数据安全/隐私保护
深度揭秘!Python加密技术的背后,AES与RSA如何守护你的数据安全
【9月更文挑战第10天】随着数字化时代的到来,数据安全成为企业和个人面临的重大挑战。Python 作为功能强大的编程语言,在数据加密领域扮演着重要角色。AES 和 RSA 是两种主流加密算法,分别以对称和非对称加密方式保障数据安全。AES(Advanced Encryption Standard)因其高效性和安全性,在数据加密中广泛应用;而 RSA 则利用公钥和私钥机制,在密钥交换和数字签名方面表现卓越。
81 3
|
2月前
|
存储 安全 数据库
双重防护,无懈可击!Python AES+RSA加密方案,构建最强数据安全堡垒
【9月更文挑战第11天】在数字时代,数据安全至关重要。AES与RSA加密技术相结合,构成了一道坚固防线。AES以其高效性保障数据加密,而RSA则确保密钥安全传输,二者相辅相成,提供双重保护。本文通过Python代码示例展示了这一加密方案的魅力,强调了其在实际应用中的重要性和安全性。使用HTTPS等安全协议传输加密密钥和密文,确保数据在数字世界中自由流通而无忧。
60 1
|
2月前
|
安全 算法 数据安全/隐私保护
黑客克星!Python加密艺术大公开,AES、RSA双剑合璧,守护你的数字世界
在这个数据泛滥的时代,数字世界既充满了知识,也潜藏安全隐患。Python 作为强大的编程语言,以其独特的加密技术为我们的信息安全保驾护航。本文将介绍 AES 和 RSA 这两种加密算法,揭示它们如何协同工作,保护你的数字世界。AES(高级加密标准)以其高效、安全著称,能将敏感信息转化为难以破解的乱码。Python 的 `pycryptodome` 库让 AES 加密变得简单易行。然而,AES 面临密钥分发难题,此时 RSA(非对称加密算法)便大显身手,通过公钥加密、私钥解密的方式确保密钥传输安全。AES 与 RSA 在 Python 中交织成一道坚不可摧的防护网,共同守护我们的数字世界。
79 0
|
存储 安全 算法
iOS中常见的几种加密方式总结!
这篇文章主要给大家介绍了关于iOS中常见的几种加密方法,其中包括 base64加密、POST加密、Token值介绍、MD5加密--(信息-摘要算法) 哈希算法之一、时间戳密码以及指纹识别等方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
1818 0
|
1月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
110 1
|
7天前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
24 9

热门文章

最新文章