【RSA】RSA加密、解密、签名与验证

您所在的位置:网站首页 rsa签名和加密区别 【RSA】RSA加密、解密、签名与验证

【RSA】RSA加密、解密、签名与验证

2023-05-31 00:59| 来源: 网络整理| 查看: 265

RSA

前言

最近要做iOS SDK的联网授权,涉及到数据安全验证,因此想到使用RSA进行签名和验证。 授权主要流程如下:

1、客户方前往我方开放平台注册授权,得到AppId和AppSecret。 2、客户方集成SDK,调用Register接口传入AppId和AppSecret。 3、SDK将AppId和客户端平台相关信息提交给服务器后台。 4、服务器下发最新服务器时间戳、sign、公钥、授权相关数据给客户端。 5、客户端使用公钥进行签名验证。 6、签名验证通过计算授权时间是否有效。

简单介绍就是服务器端生成秘钥对,使用私钥对客户端和开放平台提交的参数进行签名,然后下发签名和公钥(经过处理的字符串)到客户端,客户端验签通过后进行授权验证。

OpenSSL

使用RSA需要调用一个很重要的库OpenSSL,可以使用Cocoapods在项目中快速集成: OpenSSL库

我一般会安装如下版本:

pod 'OpenSSL-Universal', '~> 1.0.2.20' 复制代码

使用前先导入相关头文件:

#include #include #include #include #include 复制代码 公钥与私钥 1、PEM公钥和私钥文件生成

为了验证接口的正确性,我们需要先本地生成秘钥对进行本地代码测试:

1.1、在桌面创建文件夹 RSA Key ,终端CD到此文件夹。 myz@myz mediapipe % cd /Users/myz/Desktop/RSA\ Key 复制代码 1.2、终端生成1024位私钥

openssl genrsa -out rsa_private_key.pem 1024

myz@myz RSA Key % openssl genrsa -out rsa_private_key.pem 1024 Generating RSA private key, 1024 bit long modulus ........++++++ .................................++++++ e is 65537 (0x10001) myz@myz RSA Key % 复制代码 1.3、使用RSA私钥生成公钥

openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

2、通用RSA秘钥格式

将pem文件改为txt后缀打开可以看到秘钥文本

2.1、公钥 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjQRu0fImY/AVasfAneO4G8sID P3L9XDX+nZq8GBw4vlDzoWIqXGx8ETRMMRx+fdEz3Skdrlsp1+6NcYNSp0Id4b1x mRw4A5zokwN/C6vcVpLZM86Kc/q+Pi9kWkDRUm32jUmI2qWtqyXIOGZMUIfoSVe/ 9czeJ66JFX4zwlZEfwIDAQAB -----END PUBLIC KEY----- 复制代码 2.2、私钥 -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDjQRu0fImY/AVasfAneO4G8sIDP3L9XDX+nZq8GBw4vlDzoWIq XGx8ETRMMRx+fdEz3Skdrlsp1+6NcYNSp0Id4b1xmRw4A5zokwN/C6vcVpLZM86K c/q+Pi9kWkDRUm32jUmI2qWtqyXIOGZMUIfoSVe/9czeJ66JFX4zwlZEfwIDAQAB AoGAFZiWXWyIVvV8PMY0IEwpspdXQJ/C+bjNmMi5b66K4AmV/9ESVxw5YwDvi14P ayXhv6AAzEVJfIx8qwxignRKoAZ8pB1pqzFoZfudIsnQHJiukfFuriJeCxAmL6GY Yjtf0QGGqZQp5S0RUaHeYH3Z7KYztcBQP7Wdn3RYVW9VVUECQQD2/0DBeEdzLUH4 0aV8UlHV+cWAd/ODd3TWYxbJ9WJ1GnsPL70Eg38DEmw95XehReUkFpwWFLRoGhjd DbldIs5XAkEA64miXwxSGjxgjzcDM3wiZIRAljXjWeXhEugZSZgPLssp4r0Z0bdB R0t6whtzqwxPGg8opB4aDUuOjpp/A0ISGQJACDoyZv9hqeV9CBO7pmt7jFwYhxH3 y45EFwwP60RANlReewAFFMxog6qublVhab7RRiV2p4mjBMCxyVM2tHJ/WwJAbYEm qTPsM+BgMBUuetA6mSrXcD6Lfa8fbg/UOd/lJyczSQQLrfGZ+tB/uSDULPDjEcV8 apjIGehH1crERDqCeQJBAIDxsUBMiPxwDnYRf9d1QDFgRfe8XU54bpjzWCUNo0+e rVVst5NNybClxvh7gWX4PgWxR2g1uIkCecvROTRMIzo= -----END RSA PRIVATE KEY----- 复制代码 3、公钥与私钥的读取

RSA加密的public key格式有多种,常见的有两种:一种密钥头为-----BEGIN RSA PUBLIC KEY-----,一种开头为-----BEGIN PUBLIC KEY-----,二者分别对应RSA的PKCS#1和PKCS#8格式。使用OpenSSL库加载RSA的公钥时,使用的函数也不同。以字符串公钥为例,对PKCS#1格式的密钥加载使用PEM_read_bio_RSAPublicKey()函数,对PKCS#8格式公钥的加载使用PEM_read_bio_RSA_PUBKEY()函数。private key读取通常使用 PEM_read_bio_RSAPrivateKey 函数。

3.1 加载秘钥数据到BIO

将秘钥数据转换为 BIO 对象有一下两种方式:

通过BIO_new_mem_buf函数读取 // 从字符串读取 NSString *keyString = @""; const char *buffer = [keyString UTF8String]; bio = BIO_new_mem_buf(buffer, (int)strlen(buffer)); // 从字节读取 NSData *keyData = data; bio = BIO_new_mem_buf((const void*)[keyData bytes], (int)keyData.length); 复制代码 通过BIO_puts生成 // 从字节读取 NSData *keyData = data; BIO *bio = BIO_new(BIO_s_mem()); BIO_puts(bio, (void*)[keyData bytes]); 复制代码 3.2 从BIO对象读取公钥或者私钥 RSA *SLRSAReadKeyFromBIO(BIO *bio, NSString *key, BOOL isPublicKey) { if (bio == NULL) return NULL; if (!isPublicKey) {        // 读取私钥        RSA *rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);       BIO_free_all(bio);        return rsa;     }     NSString *pkcs1_header = @"-----BEGIN RSA PUBLIC KEY-----";     //    NSString *pkcs8_header = @"-----BEGIN PUBLIC KEY-----";     RSA *rsa = NULL;     if (key && [key containsString:pkcs1_header]) {         rsa = PEM_read_bio_RSAPublicKey(bio, &rsa, NULL, NULL);     }     else {         rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);     }     BIO_free_all(bio);     return rsa; } 复制代码 3.3 秘钥读取接口 RSA *SLRSAReadKey(id key, BOOL isPublicKey) {     if (!key) {         return NULL;     }     BIO *bio = NULL;     NSString *key = nil;     if ([keyObject isKindOfClass:[NSData class]]) {         NSData *keyData = (NSData*)keyObject;         bio = BIO_new_mem_buf((const void*)[keyData bytes], (int)keyData.length);     }     else if ([keyObject isKindOfClass:[NSString class]]) {        key = (NSString*)keyObject;         const char *buffer = [key UTF8String];         bio = BIO_new_mem_buf(buffer, (int)strlen(buffer));     }     if (bio == NULL) {         NSLog(@"--bio new mem buf failed--");         return NULL;     }     return SLRSAReadKeyFromBIO(bio, key, isPublicKey); } 复制代码 4、服务器公钥的组装

通常服务器返回的公钥格式为去掉header和end格式的base64字符串:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjQRu0fImY/AVasfAneO4G8sID P3L9XDX+nZq8GBw4vlDzoWIqXGx8ETRMMRx+fdEz3Skdrlsp1+6NcYNSp0Id4b1x mRw4A5zokwN/C6vcVpLZM86Kc/q+Pi9kWkDRUm32jUmI2qWtqyXIOGZMUIfoSVe/ 9czeJ66JFX4zwlZEfwIDAQAB

需要对这些字符串处理后才可以正常读入内存,如果后端有做特殊处理,客户端请做差异化处理:

NSString *SLRSAPEMKeyFromBase64(NSString *base64Key, BOOL isPublicKey) { NSMutableString *result = [NSMutableString string]; if (isPublicKey) { [result appendString:@"-----BEGIN PUBLIC KEY-----\n"]; }else{ [result appendString:@"-----BEGIN RSA PRIVATE KEY-----\n"]; } [result appendString:@""""]; int count = 0; for (int i = 0; i < [base64Key length]; ++i) { unichar c = [base64Key characterAtIndex:i]; if (c == '\n' || c == '\r') { continue; } [result appendFormat:@"%c", c]; if (++count == 64) { [result appendString:@"\n"]; [result appendString:@""""]; count = 0; } } if (isPublicKey) { [result appendString:@"\n-----END PUBLIC KEY-----"]; }else{ [result appendString:@"\n-----END RSA PRIVATE KEY-----"]; } return result; } 复制代码 加密与解密

在正确读取秘钥到内存后,我们就可以进行加解密操作了,RSA公钥和私钥都可以用来加密和解密,一般成对使用,如果使用公钥加密,则可用私钥解密,如果使用私钥加密,则可用公钥解密,通常正确的方式应该是使用公钥加密、私钥解密。

RSA加密

输入utf-8字符串加密后得到字节数据需要转为base64用于传输

// int SLRSAEncrypt(BOOL isPublic, RSA *rsa, NSString *src, NSString **dest, int padding) { if (rsa == NULL || src.length


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3