【swift 5】Swift 使用RSA算法进行数据加密,解密以及数字签名

更新时间:2020-03-11    来源:.Net开发    手机版     字体:

【www.bbyears.com--.Net开发】

RSA算法是一种非对称加密算法,要了解RSA算法,首先要知道什么是对称加密算法,什么是非对称加密算法。

1,对称加密算法

密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密。
特点:算法公开、计算量小、加密速度快、加密效率高特点。但交易双方都使用同样钥匙,安全性得不到保证。
具体算法有:DES算法,3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法。

2,非对称加密算法

非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。
特点:由于有两种密钥,其中一个是公开的,这样就消除了最终用户交换密钥的需要,更安全。但由于算法复杂,加密解密速度没有对称加密解密的速度快。
主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。

3,RSA算法

(1)RSA算法是第一个能同时用于加密和数字签名的算法。
(2)RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
(3)RSA的算法涉及三个参数,n、e1、e2。
其中,n是两个大质数p、q的积,n的二进制表示时所占用的位数,就是所谓的密钥长度。
e1和e2是一对相关的值,e1可以任意取,但要求e1与(p-1)*(q-1)互质;再选择e2,要求(e2*e1)mod((p-1)*(q-1))=1。
(n,e1),(n,e2)就是密钥对。其中(n,e1)为公钥,(n,e2)为私钥。
RSA加解密的算法完全相同,设A为明文,B为密文,则:A=B^e2 mod n;B=A^e1 mod n;(公钥加密体制中,一般用公钥加密,私钥解密)
e1和e2可以互换使用,即:
A=B^e1 mod n;B=A^e2 mod n;
(4)由于RSA的安全性依赖于大数分解,为保证安全,目前来说RSA密钥(即n)长度至少要为1024位。
(5)由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上好几倍。

4,RSA加密内容长度限制的问题

通常1024位key的最多只能加密127位数据,要解决这个问题有两种办法:
(1)自己把数据变成N个117字节的数据段来分别加密,解密也需要自己一个个解密再完成字节拼装
(2)加密的时候:使用对称加密(AES/DES etc)加密数据,然后用RSA公钥加密对称加密的密钥。
解密的时候:用RSA的私钥解密得到对称加密的密钥,然后完成反向操作得到明文。 (推荐这种方式)

5,RSA的使用场合

1,用于加密数据:比如我是公司领导,我希望员工A,B,C给我发消息的时候能够加密。那么我这边可以生成一对密钥,把公钥给ABC。A把消息使用公钥加密后发给我,我收到后使用私钥即可解密。这过程中如果加密消息被BC拦截了,虽然他们有一样的公钥,但是无法解密的。
2,用于数字签名:比如我要给A,B,C发送一段数据,但为了保证这个是我发送的,而不是别人伪造的,那么我可以附上我的数字签名。做法是对数据进行MD5之类的运算以取得数据的"指纹",再对"指纹"进行加密,加密将使用密钥对中的不公开的私钥。A,B,C收到数据后,用同样的运算获得数据指纹,再用公钥对加密指纹进行解密,比较解密结果与他自己计算出来的指纹是否一致,即可确定数据是否的确是我发送的、以及在传输过程中是否被篡改。

6,好用的RSA封装库 - Heimdall

Heimdall是一个Swift写的RSA封装类,使用它我们可以很方便进行数据加密,解密,数字签名,签名验证等操作。
地址是:GitHub/Heimdall

7,Heimdall的配置

(1)由于Heimdall使用到了CommonCrypto,所以首先要建立桥接头文件bridge.h并把CommonCrypto引入(头文件记得配置)

#import

(2)把Heimdall.swift添加到项目里,如果有import CommonCrypto,将其去掉

//import CommonCrypto

8,使用Heimdall进行数据加密,解密

由于RSA对加密数据长度有限制,所以Heimdall实际上是混合了AES和RSA这两种加密方式。
加密时:先生成一个随机的AES密钥,用这个密钥以AES方式加密数据。再用RSA的公钥加密AES密钥。整个加密生成的数据实际上包含两部分:前半部分是用RSA的公钥加密后的AES密钥,后半部分是使用AES加密的原始数据。
解密时:先使用RSA私钥把前面部分的AES密钥给解出来,再用这个AES密钥把后半部分的真实数据给解出来。

(1)服务端这边定义好publicTag和privateTag,这样就可以生成一对密钥。

为便于传输,我们把生成的publicKeyData用Base64编码成publicKeyString(String类型)


//公钥标签
let publicKeyTag = "com.111cn.public"
//私钥标签
let privateKeyTag = "com.111cn.private"
        
print("****** 服务器端开始生成一对密钥(公钥和私钥)******")
let localHeimdall = Heimdall(publicTag: publicKeyTag, privateTag: privateKeyTag,
    keySize: 1024)
        
var publicKeyString:String = ""
if let heimdall = localHeimdall, publicKeyData = heimdall.publicKeyDataX509() {
    publicKeyString = publicKeyData.base64EncodedStringWithOptions(
        NSDataBase64EncodingOptions(rawValue: 0))
            
    // 把/和+替换成下滑线,中划线是为了URL安全,
    // 接收方那边要记得转回来
    publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("/",
        withString: "_")
    publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("+",
        withString: "-")
 
    print("\n--- publicKeyString是:\n\(publicKeyString)")
}
print("\n--- 把公钥传给客户端(publicKeyTag和publicKeyString)\n\n")

(2)把publicTag和publicKeyString作为公钥分发给客户端,客户端使用公钥加密数据


print("****** 客户端使用公钥加密数据 ******")
//先把特殊字符转回来
publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("_",
    withString: "/")
publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("-",
    withString: "+")
let keyData = NSData(base64EncodedString: publicKeyString ,
    options: NSDataBase64DecodingOptions(rawValue: 0))
        
var encryptedMessage:String = ""
// 创建公钥
if let partnerHeimdall = Heimdall(publicTag: publicKeyTag, publicKeyData: keyData) {
    // 使用公钥加密需要传输的数据
    let message = "我访问过www.111cn.com"
    encryptedMessage = partnerHeimdall.encrypt(message)!
            
    print("\n--- 加密后的数据是是:\n\(encryptedMessage)")
    //print(partnerHeimdall.decrypt(encryptedMessage)) //使用公钥无法解密
}
print("\n--- 把加密后的数据传给服务端\n\n")
(3)服务端收到数据后使用密钥解密数据


print("****** 服务器端收到加密数据 ******")
if let localHeimdall2 = Heimdall(publicTag: publicKeyTag, privateTag: privateKeyTag,
    keySize: 1024) {
    //开始解密
    if let decryptedMessage = localHeimdall2.decrypt(encryptedMessage) {
        print("\n--- 解密后的数据是是:\n\(decryptedMessage)")
    }
}
(4)整个流程控制台输出如下:

原文:Swift - 使用RSA算法进行数据加密,解密以及数字签名


9,使用Heimdall进行数字签名和验证

(1)服务端给消息签名(使用的是私钥)。把消息连同签名发给客户端

//公钥标签
let publicKeyTag = "com.111cn.public"
//私钥标签
let privateKeyTag = "com.111cn.private"
        
print("****** 服务器端把消息进行签名 ******")
let localHeimdall = Heimdall(publicTag: publicKeyTag, privateTag: privateKeyTag,
    keySize: 1024)
var publicKeyString:String = ""
let message = "欢迎访问www.111cn.com" //消息
var signString:String = ""  //签名
if let heimdall = localHeimdall, publicKeyData = heimdall.publicKeyDataX509() {
    publicKeyString = publicKeyData.base64EncodedStringWithOptions(
        NSDataBase64EncodingOptions(rawValue: 0))
            
    // 把/和+替换成下滑线,中划线是为了URL安全,
    // 接收方那边要记得转回来
    publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("/",
        withString: "_")
    publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("+",
        withString: "-")
            
    signString = localHeimdall!.sign(message)!
    print("\n--- 消息是:\n\(message)")
    print("\n--- 签名是:\n\(signString)")
}
print("\n--- 把消息和签名都传给客户端\n\n")

(2)客户端收到后用公钥进行验证,确认是不是服务端发送的


print("****** 客户端验证消息和签名 ******")
//先把特殊字符转回来
publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("_",
    withString: "/")
publicKeyString = publicKeyString.stringByReplacingOccurrencesOfString("-",
    withString: "+")
let keyData = NSData(base64EncodedString: publicKeyString ,
    options: NSDataBase64DecodingOptions(rawValue: 0))
 
// 创建公钥
if let partnerHeimdall = Heimdall(publicTag: publicKeyTag, publicKeyData: keyData) {
    //进行验证
    let result = partnerHeimdall.verify(message, signatureBase64: signString)
    print("\n--- 验证结果是:\n\(result)")
}
(3)整个流程控制台输出如下:
原文:Swift - 使用RSA算法进行数据加密,解密以及数字签名

本文来源:http://www.bbyears.com/asp/86463.html

热门标签

更多>>

本类排行