RSA数学原理
上世纪70年代产生的一种加密算法。其加密方式比较特殊,需要两个密钥:公开密钥简称公钥(publickey
)和私有密钥简称私钥(privatekey
)。公钥加密,私钥解密;私钥加密,公钥解密。这个加密算法就是伟大的RSA.
互质关系:
如果两个正整数,除了1
以外,没有其他公因数,我们就称这两个数是互质关系(coprime)
欧拉函数
- 思考
计算这个值的方式叫做欧拉函数,使用:Φ(n)
表示如: 计算8的欧拉函数,和8互质的 1、2、3、4、5、6、7、8 φ(8) = 4
计算7
的欧拉函数,和7
互质的 1、2、3、4、5、6、7 φ(7) = 6
计算56
的欧拉函数 φ(56) = φ(8) * φ(7) = 4 * 6 = 24
一、当n
是质数的时候,φ(n)=n-1
。
二、如果n
可以分解成两个互质的整数之积,如n=A*B
则: φ(A*B)=φ(A)* φ(B)
根据以上两点得到: 如果N
是两个质数P1
和 P2
的乘积则 φ(N)=φ(P1)* φ(P2)=(P1-1)*(P2-1)
欧拉定理 费马小定理
image.png
欧拉定理:一:如果两个正整数m
和n
互质,那么m
的φ(n)
次方减去1
,可以被n
整除。举例子: 7 15 φ(15) = φ(3) *φ(5) = 2*4 =87**8%15 = 1
公式转换
image.png第一个都知道第二个k
不影响第三个: 两边同时m
模反元素举例子: m=4 n=15 φ(15) = 8
假设: e = 3 得到 3*d % x = 1 (ed-1)
才会被整除 所以求与=1
同理: 3*d = k*x +1
红色框替换 m**(e*d) = m
得到; 3*d = k*8+1
当k=4 d=11
所以:4 **(3*11)%15 = 4
;!
迪菲赫尔曼密钥交换
image.png如果 客户端和服务器规定好 m:3
n:17
客户端有个数13
服务器15
第一步:服务器向客服端发送6
客户端想后台发送12
然后得到最后要发送的 10
.
这里有人问?为啥不是3
因为不满足一些关系
image.png
15*13 != k *16 +1
;
终端加密
由于Mac系统内置
image.pngOpenSSL
(开源加密库),所以我们可以直接在终端上使用命令来玩RSA.OpenSSL
中RSA
算法常用指令主要有三个:
终端加密小数据 pem证书不能直接使用 在苹果中
1.生成私钥
openssl genrsa -out private.pem 1024
2.生成公钥
openssl rsa -in private.pem -pubout -out public.pem
writing RSA key
cat XXX 查看
vim message.txt 生成文本
转成text文本
openssl rsa -in private.pem -text -out private.text
writing RSA key
公钥加密:
openssl rsautl -encrypt -in message.txt -inkey public.pem -pubin -out enc.txt
私钥解密
openssl rsautl -decrypt -in enc.txt -inkey private.pem -out dec.txt
证书生成 csr cer
csr请求文件
openssl req -new -key private.pem -out rsacert.csr
签名 https协议 用这个签名 放在服务器 —>公钥
openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
生成p12文件 —>私钥
openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
crt后面要变成der文件 苹果才支持使用
openssl x509 -outform der -in rsacert.crt -out rsacert.cer
base64
// base64 可以将任意的二进制数据进行编码。 编码成为65个字符组成的文本文件。
// 0 ~ 9 a ~ z, A ~ Z + / =
// $base64 源文件 -o 目标文件 编码
// $base64 源文件 -o 目标文件 -D 解码
// 101001 010101 010100 010101
// A 字节 = =
// 010000 010000 000000 000000
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@",[self base64Encode:@"A"]);
NSLog(@"解码:%@",[self base64Decode:@"QQ=="]);
}
-(NSString *)base64Encode:(NSString *)string{
//
NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [data base64EncodedStringWithOptions:0];
}
-(NSString *)base64Decode:(NSString *)str{
NSData * data = [[NSData alloc] initWithBase64EncodedString:str options:0];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
@end
RSA代码演示
#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"
// 填充模式 kSecPaddingNone 每次解密结果是固定的
// kSecPaddingPKCS1 是随机变化的。
#define kTypeOfWrapPadding 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
RSA使用
#import "ViewController.h"
#import "RSACryptor.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//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
{
//1.加密
NSData * result = [[RSACryptor sharedRSACryptor] encryptData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"加密的结果是:%@",[result base64EncodedStringWithOptions:0]);
//2.解密
NSData * jiemi = [[RSACryptor sharedRSACryptor] decryptData:result];
NSLog(@"解密的结果:%@",[[NSString alloc] initWithData:jiemi encoding:NSUTF8StringEncoding]);
}
@end
网友评论