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

这篇具有很好参考价值的文章主要介绍了【RSA】RSA加密、解密、签名与验证。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

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

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

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

OpenSSL

使用RSA需要调用一个很重要的库OpenSSL,可以使用Cocoapods在项目中快速集成: 【RSA】RSA加密、解密、签名与验证

我一般会安装如下版本:

pod 'OpenSSL-Universal', '~> 1.0.2.20' 

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

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/bio.h> 

公钥与私钥

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-----,二者分别对应RSAPKCS#1PKCS#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 <= 0 || dest == NULL) {if (rsa) RSA_free(rsa);return -1;}int flen = RSA_size(rsa);char *dst = (char*)malloc(flen + 1);bzero(dst, flen);NSData *srcData = [src dataUsingEncoding:NSUTF8StringEncoding];int ret = -1;if (isPublic) {ret = RSA_public_encrypt((int)srcData.length, (uint8_t*)[srcData bytes], (uint8_t*)dst, rsa, padding);}else {ret = RSA_private_encrypt((int)srcData.length, (uint8_t*)[srcData bytes], (uint8_t*)dst, rsa, padding);}if (ret < 0) {isPublic ? NSLog(@"--rsa public encrypt failed--") : NSLog(@"--ras private encrypt failed--");RSA_free(rsa);free(dst);return ret;}NSData *encryptData = [NSData dataWithBytes:(const void*)dst length:sizeof(char)*flen];*dest = [encryptData base64EncodedStringWithOptions:0];RSA_free(rsa);free(dst);return ret;
} 

RSA解密

需要解密的密文一般是Base64格式,需要先base64解码在进行rsa解密,解密字节可以转换为对应的格式字符串用于显示

int SLRSADecrypt(BOOL isPublic, RSA *rsa, NSString *src, NSString **dest, int padding) {if (rsa == NULL || src.length <= 0 || dest == NULL) {if (rsa) RSA_free(rsa);return -1;}int flen = RSA_size(rsa);char *dst = (char*)malloc(flen + 1);bzero(dst, flen);NSData *srcData = [[NSData alloc]initWithBase64EncodedString:src options:0];int ret = -1;if (isPublic) {ret = RSA_public_decrypt((int)srcData.length, (uint8_t*)[srcData bytes], (uint8_t*)dst, rsa, padding);}else {ret = RSA_private_decrypt((int)srcData.length, (uint8_t*)[srcData bytes], (uint8_t*)dst, rsa, padding);}if (ret < 0) {isPublic ? NSLog(@"--rsa public encrypt failed--") : NSLog(@"--ras private encrypt failed--");RSA_free(rsa);free(dst);return ret;}NSData *decryptData = [NSData dataWithBytes:(const void*)dst length:sizeof(char)*flen];*dest = [[NSString alloc]initWithData:decryptData encoding:NSUTF8StringEncoding];RSA_free(rsa);free(dst);return ret;
} 

签名与验证

RSA 加密方案和 RSA 签名方案是不同的,通常是私钥负责签名,公钥负责验证。

私钥签名

私钥签名通常放在服务器端,签名后服务器下发sign和公钥给客户端,客户端进行验签

// sha1签名,输出签名后的base64字符串
int SLRSASha1SignWithKey(id key, NSString *src, NSString **sign) {if ( !key || src.length <= 0 || sign == NULL) {return -1;}RSA *rsa = SLRSAReadKey(key, NO);if (rsa == NULL) {NSLog(@"--read rsa private key from bio failed--");return -1;}NSData *srcData = [src dataUsingEncoding:NSUTF8StringEncoding];unsigned char digest[SHA_DIGEST_LENGTH];SHA1((const unsigned char *) [srcData bytes], (size_t)srcData.length, digest);unsigned char *signValue = (unsigned char *)malloc(256);unsigned int sign_len;int ret = RSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH, signValue, &sign_len, rsa);if (ret == 1) {NSData* data = [NSData dataWithBytes:signValue length:sign_len];*sign = [data base64EncodedStringWithOptions:0];}free(signValue);RSA_free(rsa);return ret;
} 

公钥验证

客户端验证签名通过后可以进行其他操作

// 结果返回1则验证正确
int SLRSASha1VerifyWithPublicKey(id key, NSString *src, NSString *sign) {if ( !key || src.length <= 0 || sign.length <= 0) {return -1;}RSA *rsa = SLRSAReadKey(key, YES);if (rsa == NULL) {NSLog(@"--read rsa public key from bio failed--");return -1;}NSData *srcData = [src dataUsingEncoding:NSUTF8StringEncoding];unsigned char digest[SHA_DIGEST_LENGTH];SHA1((const unsigned char *) [srcData bytes], (size_t)srcData.length, digest);//SHA_CTX sha_ctx = { 0 };
//unsigned char digest[SHA_DIGEST_LENGTH];
//int rc = 1;
//rc = SHA1_Init(&sha_ctx);
//if (1 != rc) { return NO; }
//
//rc = SHA1_Update(&sha_ctx, [srcData bytes], srcData.length);
//if (1 != rc) { return NO; }
//
//rc = SHA1_Final(digest, &sha_ctx);
//if (1 != rc) { return NO; }// 将base64签名转换为字节NSData *signData = [[NSData alloc]initWithBase64EncodedString:sign options:0];int ret = RSA_verify(NID_sha1, digest, SHA_DIGEST_LENGTH, (const uint8_t*)[signData bytes], (uint32_t)signData.length, rsa);RSA_free(rsa);return ret;
} 

小结

RSA非对称加密算法在日常通讯安全中有着广泛的应用,程序员应该掌握并灵活运用来解决日常问题。本章只是对RSA加解密、签名与验证的基本使用做了一下演示,后续会进一步对RSA算法和OpenSSL开源库进行研究并更新文章。文章来源地址https://www.toymoban.com/news/detail-405382.html

到了这里,关于【RSA】RSA加密、解密、签名与验证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 用RSA进行加解密和数字签名

    1.选择一对素数p,q 2.n=p*q 3.φ(n)=(n-1)(q-1) 4.找e(加密秘钥encrypt),使e与φ(n)互质且 1eφ(n) 5.计算d(解密密钥decrypt),d * e ≡ 1 mod φ(n), ≡为互余符号,即 (d * e) mod φ(n)= 1 6.公钥(e,n) 私钥(d,n) 7.设明文m,密文c,明文加密,密文c = m^e mod n 8.密文解密,明文m = c^d mod n 例:e=3 p=5 q=11 m=1

    2024年02月10日
    浏览(36)
  • RSA双向加解密(公钥加密-私钥解密;私钥加密-公钥解密)

            非对称加密算法中,提供一个公钥一个私钥。一般情况下,采用公钥加密、私钥解密的方式。         假设有这样一个场景:服务A与服务B需要通信,通信内容为了安全需要进行加密传输,并且服务A与服务B不能互相持有对方的钥匙。         我首先想到的是

    2024年02月11日
    浏览(62)
  • RSA加密/解密

    1.1、RSA算法介绍 RSA加密算法是一种可逆的非对称加密算法,即RSA加密时候用的密钥(公钥)和RSA解密时用的密钥(私钥)不是同一把。基本原理是将两个很大的质数相乘很容易得到乘积,但是该乘积分解质因数却很困难。RSA算法被广泛的用于加密解密和RSA签名/验证等领域。

    2024年02月06日
    浏览(46)
  • Python RSA加密解密

    一、RSA加密算法 RSA加密算法是一种非对称加密算法,加密的秘钥是由公钥和私钥两部分组成秘钥对,公钥用来加密消息,私钥用来解密消息,公钥是公开的,给对方进行加密,私钥则是用户自己保留,用来对加密的数据进行解密。 公钥pem文件格式:以-----BEGIN PUBLIC KEY-----标记

    2024年02月10日
    浏览(45)
  • RSA加密,解密,加签及验签

    目录 1.说明 2.加密和加签的区别 3.后端加密,解密,加签及验签示例 4.前端加密,解密,加签及验签示例 5.前端加密,后端解密,前端加签,后端验签 6.注意事项 1.说明 RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥

    2024年02月20日
    浏览(56)
  • 使用非对称加密(RSA) 实现前端加密后端解密

    数据加密方式有: 单向加密、对称加密、非对称加密、加密盐、散列函数、数字签名。 1、单向加密 单向加密通过对数据进行摘要计算生成密文,密文不可逆推还原。只能加密,不能解密,常用于提取数据的指纹信息以此来验证数据的完整性。但是会引发雪崩效应(雪崩效应

    2024年02月08日
    浏览(64)
  • RSA 加密解密算法实现(简单,易懂)!!!

    目录 一、什么是RSA算法 1.对称加密 2.非对称加密 3.非对称加密的应用 二、RSA算法的基础操作步骤 1.生成公钥和私钥 2.用公钥加密信息  3.用私钥解密信息 三、AC代码 六、RSA算法的测试  七、共勉     在计算机中常用的加密算法分为两类: 对称加密算法和非对称加密算法。

    2024年01月20日
    浏览(66)
  • RSA之前端加密后端解密

    RSA加密解密方式有: (1)公钥加密,私钥解密; (2)私钥加密,公钥解密; 此文章中以下我使用的是 前端公钥加密,后端私钥解密 ; http://web.chacuo.net/netrsakeypair 生成对应的公钥和私钥 前端加密js文件 : 链接: https://pan.baidu.com/s/1NIMayTcmjbMOf7BqPhPQoA 提取码: t7an 下载js文件并

    2024年02月21日
    浏览(51)
  • 一文搞懂对称加密与非对称加密(RSA)、信息摘要、数字签名

    目录 一、对称加密与非对称加密 二、信息摘要 三、数字签名 四、小练习 对称加密: 加密和解密使用同一个秘钥(如加密方式为+1,那解密方式为-1)常见的对称加密算法:DES,AES,3DES等 非对称加密: 加密和解密使用不同密钥。两个密钥:公共密钥和私有密钥。通常将公钥

    2024年02月16日
    浏览(50)
  • js实现rsa密钥的加密、解密与生成

    今天想用js实现rsa的加解密的,在网上找了好久,下载啊什么的,十分麻烦,今天我也不bb的直接放代码 rsa.html 生成完了后,可以去在线rsa网站上检测一下,RSA在线加解密 下载链接: rsa.zip - 蓝奏云 备用下载链接: 百度网盘 密码1234 参考文献: travist/jsencrypt: (github.com)

    2024年02月16日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包