欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Swift - 第三方加密库CryptoSwift使用详解3(AES加密与解密)

程序员文章站 2022-04-11 17:47:42
...

用Swift 进行AES 加密、解密

Swift - 第三方加密库CryptoSwift使用详解3(AES加密与解密)

嗯_挺好的关注

0.3362017.08.30 17:08:01字数 140阅读 4,766

最近在公司在用Swift 翻 oc 的项目,由于原来的加密方式都是用OC写的,现在要Swift

发篇文章,大家以后进行加密的时候,希望可以方便一些,不用再这么费劲

1.导入第三方库CryptoSwift
import CryptoSwift
CryptoSwift源码地址

算了,话不多说,直接上代码

    public static func Endcode_AES_ECB(strToEncode:String)->String {
        // 从String 转成data
        let data = strToEncode.data(using: String.Encoding.utf8)
        
        // byte 数组
        var encrypted: [UInt8] = []
        do {
            encrypted = try AES(key: key, iv: iv, blockMode: .CBC, padding: PKCS7()).encrypt(data!.bytes)
        } catch {
        }
        
        let encoded =  Data(encrypted)
        //加密结果要用Base64转码
        return encoded.base64EncodedString()
    }
    
    //  MARK:  AES-ECB128解密
    public static func Decode_AES_ECB(strToDecode:String)->String {
        //decode base64
        let data = NSData(base64Encoded: strToDecode, options: NSData.Base64DecodingOptions.init(rawValue: 0))
        
        // byte 数组
        var encrypted: [UInt8] = []
        let count = data?.length
        
        // 把data 转成byte数组
        for i in 0..<count! {
            var temp:UInt8 = 0
            data?.getBytes(&temp, range: NSRange(location: i,length:1 ))
            encrypted.append(temp)
        }
        
        // decode AES
        var decrypted: [UInt8] = []
        do {
            decrypted = try AES(key: key, iv: iv, blockMode:.CBC, padding: PKCS7()).decrypt(encrypted)
        } catch {
        }
        
        // byte 转换成NSData
        let encoded = Data(decrypted)
        var str = ""
        //解密结果从data转成string
        str = String(bytes: encoded.bytes, encoding: .utf8)!
        return str
    }

DEMO地址
后续还会更新其他加密方式 ,以及原生加密等等,大家如果写了其他的加密,可以@我一下,一起学习

六、AES 加密与解密

1,AES 介绍

  • 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称 Rijndael 加密法,是美国联邦*采用的一种区块加密标准。
  • 该标准是用来替代原先的 DES,现已经被多方分析且广为全世界所使用,成为对称**加密中最流行的算法之一。
  • AES 采用对称分组密码*,加密数据块分组长度必须为 128 比特,**长度可以是 128 比特、192 比特、256 比特中的任意一个(如果数据块及**长度不足时,会补齐)

 

2,加密模式介绍

AES 作为一种分组加密算法为了适应不同的安全性要求和传输需求允许在多种不同的加密模式下工作:

 

(1)ECB 模式(电子密码本模式:Electronic codebook

  • ECB 是最简单的块密码加密模式,加密前根据加密块大小(如 AES 为 128 位)分成若干块,之后将每块使用相同的**单独加密,解密同理。
  • ECB 模式由于每块数据的加密是独立的因此加密和解密都可以并行计算。
  • ECB 模式最大的缺点是相同的明文块会被加密成相同的密文块,这种方法在某些环境下不能提供严格的数据保密性。


(2)CBC 模式(密码分组链接:Cipher-block chaining

  • CBC 模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。
  • CBC 模式相比 ECB 有更高的保密性,但由于对每个数据块的加密依赖于前一个数据块的加密,所以加密无法并行。
  • CBC 模式与 ECB 一样在加密前需要对数据进行填充,不是很适合对流数据进行加密。 

 

(3)CTR 模式(计算器模式:Counter

  • 计算器模式不常见,在 CTR 模式中, 有一个自增的算子,这个算子用**加密之后的输出和明文异或的结果得到密文,相当于一次一密。
  • 这种加密方式简单快速,安全可靠,而且可以并行加密。
  • 但是在计算器不能维持很长的情况下,**只能使用一次。

 

(4)CFB 模式(密文反馈:Cipher feedback

  • 与 ECB 和 CBC 模式只能够加密块数据不同,CFB 能够将块密文(Block Cipher)转换为流密文(Stream Cipher)。
  • CFB 的加密工作分为两部分:先将前一段加密得到的密文再加密;接着将第 1 步加密得到的数据与当前段的明文异或。
  • 由于加密流程和解密流程中被块加密器加密的数据是前一段密文,因此即使明文数据的长度不是加密块大小的整数倍也是不需要填充的,这保证了数据长度在加密前后是相同的。
  • CFB 模式非常适合对流数据进行加密,解密可以并行计算。

 

(5)OFB 模式(输出反馈:Output feedback

  • OFB 是先用块加密器生成**流(Keystream),然后再将**流与明文流异或得到密文流,解密是先用块加密器生成**流,再将**流与密文流异或得到明文,由于异或操作的对称性所以加密和解密的流程是完全一样的。
  • OFB 与 CFB 一样都非常适合对流数据的加密。
  • OFB 由于加密和解密都依赖与前一段数据,所以加密和解密都不能并行。

 

3,关于**长度

(1)在进行 AES 加密时,CryptoSwift 会根据**的长度自动选择对应的加密算法(AES128AES192AES256

  • AES-128 = 16 bytes
  • AES-192 = 24 bytes
  • AES-256 = 32 bytes

 

(2)这里我们以 ECB 模式为例。由于**为 16 个字符(字节),则自动采用 aes128 加密。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

do {

    let str = "欢迎访问 hangge.com"

    print("原始字符串:\(str)")

     

    let key = "hangge.com123456"

    print("key**:\(key)")

     

    //使用AES-128-ECB加密模式

    let aes = try AES(key: key.bytes, blockMode: .ECB)

     

    //开始加密

    let encrypted = try aes.encrypt(str.bytes)

    print("加密结果(base64):\(encrypted.toBase64()!)")

     

    //开始解密

    let decrypted = try aes.decrypt(encrypted)

    print("解密结果:\(String(data: Data(decrypted), encoding: .utf8)!)")

} catch { }

运行结果如下:

Swift - 第三方加密库CryptoSwift使用详解3(AES加密与解密)

 

(3)如果**长度不够 1624 或 32 字节,可以使用 zeroPadding 将其补齐至 blockSize 的整数倍。

zeroPadding 补齐规则:
将长度补齐至 blockSize 参数的整数倍。比如我们将 blockSize 设置为 AES.blockSize16)。

  • 如果长度小于 16 字节:则尾部补 0,直到满足 16 字节。
  • 如果长度大于等于 16 字节,小于 32 字节:则尾部补 0,直到满足 32 字节。
  • 如果长度大于等于 32 字节,小于 48 字节:则尾部补 0,直到满足 48 字节。 以此类推......

这里还是以 ECB 模式为例,假设我们**只有 9 个字节,通过 zeroPadding 补齐到 16 个字节。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

do {

    let str = "欢迎访问 hangge.com"

    print("原始字符串:\(str)")

     

    let key = "hangge666"

    print("key**:\(key)")

     

    //使用AES-128-ECB加密模式

    let aes = try AES(key: Padding.zeroPadding.add(to: key.bytes, blockSize: AES.blockSize),

                      blockMode: .ECB)

     

    //开始加密

    let encrypted = try aes.encrypt(str.bytes)

    print("加密结果(base64):\(encrypted.toBase64()!)")

     

    //开始解密

    let decrypted = try aes.decrypt(encrypted)

    print("解密结果:\(String(data: Data(decrypted), encoding: .utf8)!)")

} catch { }

运行结果如下:

Swift - 第三方加密库CryptoSwift使用详解3(AES加密与解密)

 

4,CBC 模式的便捷写法

(1)我们知道使用 CBC 模式加密时,除了提供一个**(key)外,还需要一个**偏移量(iv)。这个 Cipher 的完整写法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

do {

    let str = "欢迎访问 hangge.com"

    print("原始字符串:\(str)")

 

    let key = "hangge.com123456"

    print("key**:\(key)")

     

    let iv = "1234567890123456"

    print("**偏移量:\(iv)")

     

    //使用AES-128-CBC加密模式

    let aes = try AES(key: key.bytes, blockMode: .CBC(iv: iv.bytes))

     

    //开始加密

    let encrypted = try aes.encrypt(str.bytes)

    print("加密结果(base64):\(encrypted.toBase64()!)")

     

    //开始解密

    let decrypted = try aes.decrypt(encrypted)

    print("解密结果:\(String(data: Data(decrypted), encoding: .utf8)!)")

} catch { }

运行结果如下:

Swift - 第三方加密库CryptoSwift使用详解3(AES加密与解密)

 

(2)CBC 模式的 Cipher 还可以这么写,效果同上面的那个是一样的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

do {

    let str = "欢迎访问 hangge.com"

    print("原始字符串:\(str)")

 

    let key = "hangge.com123456"

    print("key**:\(key)")

     

    let iv = "1234567890123456"

    print("**偏移量:\(iv)")

     

    //使用AES-128-CBC加密模式

    let aes = try AES(key: key, iv: iv)

     

    //开始加密

    let encrypted = try aes.encrypt(str.bytes)

    print("加密结果(base64):\(encrypted.toBase64()!)")

     

    //开始解密

    let decrypted = try aes.decrypt(encrypted)

    print("解密结果:\(String(data: Data(decrypted), encoding: .utf8)!)")

} catch { }

 

5,随机生成**偏移量

除了 ECB 模式外,其它模式不仅需要提供**(key),还需要一个**偏移量(iv)。如果觉得自己定义 iv 麻烦,可以通过 AES.randomIV() 方法来自动生成。

1

2

3

//创建一个16字节的随机**偏移量

let iv = AES.randomIV(AES.blockSize)

print(iv)

运行结果如下:

Swift - 第三方加密库CryptoSwift使用详解3(AES加密与解密)

 

6,String 的加密与解密

(1)上面的样例中,我们都是先定义一个 Cipher,然后使用这个 Cipher 的 encrypt 和 decrypt 方法对字符串进行加密与解密。但这过程中我们还需要手动进行一些数据转换工作:

  • 加密时需要先将字符串转为字节数组([UInt8])。加密后又需要将结果从字节数组转为 base64 的字符串形式。
  • 解密后同样需要将结果从字节数组转为字符串形式。

1

2

3

4

5

6

7

8

9

10

11

//使用AES-128-CBC加密模式的Cipher

let aes = try AES(key: key, iv: iv)

 

//方式一

let str = "欢迎访问 hangge.com"

             

let encrypted = try aes.encrypt(str.bytes)

print("加密结果(base64):\(encrypted.toBase64()!)")

 

let decrypted = try aes.decrypt(encrypted)

print("解密结果:\(String(data: Data(decrypted), encoding: .utf8)!)")


(2)而 CryptoSwift 其实对 String 做了扩展,增加了许多加密解密的相关方法。我们只需要传入 Cipher 即可,不再需要进行这些数据转换工作了。

1

2

3

4

5

6

7

8

9

10

11

//使用AES-128-CBC加密模式的Cipher

let aes = try AES(key: key, iv: iv)

 

//方式二

let str = "欢迎访问 hangge.com"

 

let encrypted = try str.encryptToBase64(cipher: aes)!

print("加密结果(base64):\(encrypted)")

             

let decrypted = try encrypted.decryptBase64ToString(cipher: aes)

print("解密结果:\(decrypted)")

 

7,增量更新

使用 Cryptor 实例可以进行增量操作,即每次只加密或解密一部分数据,这样对于大文件可以有效地节省内存占用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

do {

    //创建一个用于增量加密的Cryptor实例

    var encryptor = try AES(key: "hangge.com123456", iv: "drowssapdrowssap").makeEncryptor()

     

    var ciphertext = Array<UInt8>()

    //合并每个部分的结果

    ciphertext += try encryptor.update(withBytes: Array("欢迎访问".utf8))

    ciphertext += try encryptor.update(withBytes: Array(" ".utf8))

    ciphertext += try encryptor.update(withBytes: Array("hangge.com".utf8))

    //结束

    ciphertext += try encryptor.finish()

     

    //输出完整的结果(base64字符串形式)

    print(ciphertext.toBase64()!)

} catch {

    print(error)

}

运行结果如下:

Swift - 第三方加密库CryptoSwift使用详解3(AES加密与解密)

 

8,补码方式(padding)

(1)默认情况下,CryptoSwift 使用 PKCS7 进行填充。比如下面两个定义方式是一样的。

1

2

3

let aes1 = try AES(key: key, blockMode: .CBC(iv: iv))

         

let aes2 = try AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)


(2)我们也可以根据需求改成其它的填充方式。具体有:

  • pkcs5
  • pkcs7
  • zeroPadding
  • noPadding


原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1869.html