Project Icon

CryptoSwift

功能全面的纯Swift加密库

CryptoSwift是一个纯Swift实现的开源加密库,提供哈希、CRC校验、对称加密、RSA、消息认证等多种加密功能。支持iOS、Android、macOS等平台,API简洁易用,可便捷进行字符串和数据加密。该库支持增量更新和流式处理,性能良好,适用于各类Swift项目的加密需求。

平台

Swift 支持 Swift Package Manager 兼容 CocoaPods 兼容 Carthage 兼容

CryptoSwift

用 Swift 实现的与加密相关的函数和助手,适用于 Swift。(#PureSwift)

注意main 分支遵循最新发布的 Swift 版本。如果您需要较早版本的 Swift,请在 Podfile 中指定其版本或使用该版本的分支代码。旧分支不受支持。查看版本了解详情。


需求 | 特性 | 贡献 | 安装 | Swift 版本 | 使用方法 | 作者 | 许可证 | 更新日志

支持与赞助商

项目的财务可持续性得益于我们的 GitHub 赞助商 持续的贡献

高级赞助商

Emerge Tools 是一套革命性产品,旨在为移动应用及其开发团队提供超级动力。

www.emergetools.com/

需求

心情愉悦

特性

  • 易于使用
  • 为 String 和 Data 提供便利扩展
  • 支持增量更新(流等)
  • 支持 iOS、Android、macOS、AppleTV、watchOS、Linux

哈希(摘要)

MD5 | SHA1 | SHA2-224 | SHA2-256 | SHA2-384 | SHA2-512 | SHA3

循环冗余校验 (CRC)

CRC32 | CRC32C | CRC16

密码

AES-128, AES-192, AES-256 | ChaCha20 | XChaCha20 | Rabbit | Blowfish

RSA(公钥加密算法)

加密、签名

消息认证器

Poly1305 | HMAC (MD5, SHA1, SHA256) | CMAC | CBC-MAC

密码操作模式

  • 电子密码本 (ECB)
  • 密码块链接 (CBC)
  • 传播密码块链接 (PCBC)
  • 密码反馈 (CFB)
  • 输出反馈 (OFB)
  • 计数器模式 (CTR)
  • 伽罗瓦/计数器模式 (GCM)
  • 带密码块链接消息认证码的计数器 (CCM)
  • OCB 认证加密算法 (OCB)

基于密码的密钥派生函数

  • PBKDF1(基于密码的密钥派生函数 1)
  • PBKDF2(基于密码的密钥派生函数 2)
  • HKDF(基于 HMAC 的提取和扩展密钥派生函数)
  • Scrypt(Scrypt 基于密码的密钥派生函数)

数据填充

带关联数据的认证加密(AEAD)

为什么

为什么? 因为我能做到

如何参与?

你想帮忙,太好了!继续 fork 我们的仓库,做出你的修改并发送给我们一个拉取请求。

贡献

查看 CONTRIBUTING.md 了解如何帮助 CryptoSwift 的更多信息。

安装

强化运行时(macOS)和 Xcode

如果应用使用本地运行签名签名证书并启用了强化运行时,二进制 CryptoSwift.xcframework(由 Swift Package Manager 包集成使用)将无法在你的应用中正确加载。Xcode 可能会这样设置。要解决这个问题,你有两个选择:

  • 使用适当的签名证书,例如 Development <- 这是正确的做法
  • 使用 禁用库验证com.apple.security.cs.disable-library-validation 权限

Xcode 项目

要安装 CryptoSwift,将其作为子模块添加到你的项目(在顶级项目目录):

git submodule add https://github.com/krzyzanowskim/CryptoSwift.git

建议启用整模块优化以获得更好的性能。未优化的构建会导致性能明显变差。

Swift Package Manager

你可以使用 Swift Package Manager 并在 Package.swift 中通过添加以下内容指定依赖:

.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.8.3")

参见:Package.swift - 手册

注意:Swift Package Manager 在 Xcode 调试构建中使用调试配置,这可能会导致性能显著下降(最多 10000 倍)。发布构建中的性能特征有所不同。要解决这个问题,请考虑嵌入下面描述的 CryptoSwift.xcframework

CocoaPods

你可以使用 CocoaPods

pod 'CryptoSwift', '~> 1.8.3'

请记住,CocoaPods 将在没有整模块优化的情况下构建 CryptoSwift,这可能会影响性能。你可以在安装后手动更改它,或使用 cocoapods-wholemodule 插件。

Carthage

你可以使用 Carthage。 在 Cartfile 中指定:

github "krzyzanowskim/CryptoSwift"

运行 carthage 构建框架,并将构建的 CryptoSwift.framework 拖入你的 Xcode 项目。按照构建说明进行操作。常见问题

XCFramework

XCFrameworks 需要 Xcode 11 或更高版本,它们可以像我们习惯集成 .framework 格式一样进行集成。 请使用脚本 scripts/build-framework.sh 生成二进制 CryptoSwift.xcframework 存档,你可以在 Xcode 中将其用作依赖项。

CryptoSwift.xcframework 是一个发布(优化)二进制文件,提供最佳可用的 Swift 代码性能。

Screen Shot 2020-10-27 at 00 06 32

嵌入式框架

嵌入式框架要求最低部署目标为 iOS 11.0 或 macOS Sierra (10.13)。将 CryptoSwift.xcodeproj 文件拖入你的 Xcode 项目,并将适当的框架作为依赖项添加到你的目标。现在选择你的应用并选择应用目标的 General 选项卡。找到 嵌入式二进制文件 并按 "+",然后选择 `CryptoSwift

  • Swift 1.2: 分支 swift12 版本 <= 0.0.13
  • Swift 2.1: 分支 swift21 版本 <= 0.2.3
  • Swift 2.2, 2.3: 分支 swift2 版本 <= 0.5.2
  • Swift 3.1, 分支 swift3 版本 <= 0.6.9
  • Swift 3.2, 分支 swift32 版本 = 0.7.0
  • Swift 4.0, 分支 swift4 版本 <= 0.12.0
  • Swift 4.2, 分支 swift42 版本 <= 0.15.0
  • Swift 5.0, 分支 swift5 版本 <= 1.2.0
  • Swift 5.1, 分支 swift5 版本 <= 1.3.3
  • Swift 5.3 及更新版本, 分支 main

使用方法

基础知识
import CryptoSwift

CryptoSwift使用字节数组(即Array<UInt8>)作为所有操作的基本类型。任何数据都可以转换为字节流。你会发现一些接受StringData的便捷函数,它们会在内部转换为字节数组。

数据类型转换

为了方便使用,CryptoSwift提供了两个函数,可以轻松地将字节数组转换为Data或将Data转换为字节数组:

从字节创建Data:

let data = Data([0x01, 0x02, 0x03])

Data转换为Array<UInt8>

let bytes = data.bytes                     // [1,2,3]

十六进制编码:

let bytes = Array<UInt8>(hex: "0x010203")  // [1,2,3]
let hex   = bytes.toHexString()            // "010203"

String构建字节

let bytes: Array<UInt8> = "cipherkey".bytes  // Array("cipherkey".utf8)

另外...查看使用Base64编码数据的辅助函数:

"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher)
"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher)
bytes.toBase64()
计算摘要

对数据或字节数组(即Array<UInt8>)进行哈希处理

/* Hash结构体用法 */
let bytes: Array<UInt8> = [0x01, 0x02, 0x03]
let digest = input.md5()
let digest = Digest.md5(bytes)
let data = Data([0x01, 0x02, 0x03])

let hash = data.md5()
let hash = data.sha1()
let hash = data.sha224()
let hash = data.sha256()
let hash = data.sha384()
let hash = data.sha512()
do {
    var digest = MD5()
    let partial1 = try digest.update(withBytes: [0x31, 0x32])
    let partial2 = try digest.update(withBytes: [0x33])
    let result = try digest.finish()
} catch { }

对字符串进行哈希处理并打印结果

let hash = "123".md5() // "123".bytes.md5()
计算CRC
bytes.crc16()
data.crc16()

bytes.crc32()
data.crc32()
消息验证器
// 为消息计算消息认证码(MAC)
let key: Array<UInt8> = [1,2,3,4,5,6,7,8,9,10,...]

try Poly1305(key: key).authenticate(bytes)
try HMAC(key: key, variant: .sha256).authenticate(bytes)
try CMAC(key: key).authenticate(bytes)
基于密码的密钥派生函数
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)

let key = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha256).calculate()
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)
// Scrypt实现不支持并行化工作,因此`p`参数即使在多核系统中也会增加工作时间
let key = try Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1).calculate()
基于HMAC的密钥派生函数
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)

let key = try HKDF(password: password, salt: salt, variant: .sha256).calculate()
数据填充

某些内容加密算法假设输入长度是k个八位字节的倍数,其中k大于1。对于这样的算法,需要对输入进行填充。

Padding.pkcs7.add(to: bytes, blockSize: AES.blockSize)

使用密码

ChaCha20
let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message)
let decrypted = try ChaCha20(key: key, iv: iv).decrypt(encrypted)
Rabbit
let encrypted = try Rabbit(key: key, iv: iv).encrypt(message)
let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted)
Blowfish
let encrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(message)
let decrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
AES

关于填充的注意事项:手动填充数据是可选的,CryptoSwift默认使用PKCS7填充。如果你需要手动禁用/启用填充,可以通过设置__AES__类的参数来实现

AES加密的变体(AES-128、AES-192、AES-256)取决于给定的密钥长度:

  • AES-128 = 16字节
  • AES-192 = 24字节
  • AES-256 = 32字节

AES-256示例

let encryptedBytes = try AES(key: [1,2,3,...,32], blockMode: CBC(iv: [1,2,3,...,16]), padding: .pkcs7)

完整示例:

let password: [UInt8] = Array("s33krit".utf8)
let salt: [UInt8] = Array("nacllcan".utf8)

/* 从`密码`生成密钥。如果已经有密钥,则可选 */
let key = try PKCS5.PBKDF2(
    password: password,
    salt: salt,
    iterations: 4096,
    keyLength: 32, /* AES-256 */
    variant: .sha256
).calculate()

/* 生成随机IV值。IV是公开值。需要生成或从其他地方获取 */
let iv = AES.randomIV(AES.blockSize)

/* AES加密器实例 */
let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7)

/* 加密数据 */
let inputData = Data()
let encryptedBytes = try aes.encrypt(inputData.bytes)
let encryptedData = Data(encryptedBytes)

/* 解密数据 */
let decryptedBytes = try aes.decrypt(encryptedData.bytes)
let decryptedData = Data(decryptedBytes)
一次性操作
do {
    let aes = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap") // aes128
    let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8))
} catch { }
增量更新

增量操作使用Cryptor实例,一次加密/解密一部分,这样可以为大文件节省内存。

do {
    var encryptor = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap").makeEncryptor()

    var ciphertext = Array<UInt8>()
    // 聚合部分结果
    ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8))
    ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8))
    ciphertext += try encryptor.update(withBytes: Array("ornare vel eu leo.".utf8))
    // 最后完成
    ciphertext += try encryptor.finish()

    print(ciphertext.toHexString())
} catch {
    print(error)
}
AES高级用法
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]

let key: Array<UInt8> = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
let iv: Array<UInt8> = // `AES.blockSize`长度的随机字节

do {
    let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input)
    let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
} catch {
    print(error)
}

不带数据填充的AES

let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let encrypted: Array<UInt8> = try! AES(key: Array("secret0key000000".utf8), blockMode: CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input)

使用便捷扩展

let plain = Data([0x01, 0x02, 0x03])
let encrypted = try! plain.encrypt(ChaCha20(key: key, iv: iv))
let decrypted = try! encrypted.decrypt(ChaCha20(key: key, iv: iv))
AES-GCM

伽罗瓦/计数器模式(GCM)加密的结果是密文和认证标签,后者用于解密。

加密

do {
    // 在组合模式下,认证标签直接附加到加密消息后。这通常是你想要的。
    let gcm = GCM(iv: iv, mode: .combined)
    let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
    let encrypted = try aes.encrypt(plaintext)
    let tag = gcm.authenticationTag
} catch {
    // 失败
}

解密

do {
    // 在组合模式下,认证标签附加在加密消息后。这通常是你想要的。
    let gcm = GCM(iv: iv, mode: .combined)
    let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
    return try aes.decrypt(encrypted)
} catch {
    // 失败
}

注意:GCM实例不能重复使用。所以你不能使用同一个GCM实例进行加密和解密。

AES-CCM

带密码块链消息认证码的计数器模式(CCM)加密的结果是密文和认证标签,后者用于解密。

do {
    // 认证标签附加在加密消息后。
	let tagLength = 8
	let ccm = CCM(iv: iv, tagLength: tagLength, messageLength: ciphertext.count - tagLength, additionalAuthenticatedData: data)
    let aes = try AES(key: key, blockMode: ccm, padding: .noPadding)
    return try aes.decrypt(encrypted)
} catch {
    // 失败
}

请查看文档或CCM规范以了解CCM的有

let encrypt = try AEADChaCha20Poly1305.encrypt(plaintext, key: key, iv: nonce, authenticationHeader: header)
let decrypt = try AEADChaCha20Poly1305.decrypt(ciphertext, key: key, iv: nonce, authenticationHeader: header, authenticationTag: tagArr: tag)
RSA

从参数初始化RSA

let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]

let n: Array<UInt8> = // RSA模数
let e: Array<UInt8> = // RSA公开指数
let d: Array<UInt8> = // RSA私有指数

let rsa = RSA(n: n, e: e, d: d)

do {
    let encrypted = try rsa.encrypt(input)
    let decrypted = try rsa.decrypt(encrypted)
} catch {
    print(error)
}

RSA密钥生成

let rsa = try RSA(keySize: 2048) // 这将生成具有给定大小的模数、公开指数和私有指数

RSA加密和解密示例

// Alice生成一个私钥
let alicesPrivateKey = try RSA(keySize: 1024)
    
// Alice与Bob分享她的**公钥**
let alicesPublicKeyData = try alicesPrivateKey.publicKeyExternalRepresentation()
    
// Bob接收Alice公钥的原始外部表示并导入它
let bobsImportOfAlicesPublicKey = try RSA(rawRepresentation: alicesPublicKeyData)
    
// Bob现在可以使用Alice的公钥为她加密一条消息
let message = "Hi Alice! This is Bob!"
let privateMessage = try bobsImportOfAlicesPublicKey.encrypt(message.bytes)
    
// 这会产生一些加密输出,如下所示
// URcRwG6LfH63zOQf2w+HIllPri9Rb6hFlXbi/bh03zPl2MIIiSTjbAPqbVFmoF3RmDzFjIarIS7ZpT57a1F+OFOJjx50WYlng7dioKFS/rsuGHYnMn4csjCRF6TAqvRQcRnBueeINRRA8SLaLHX6sZuQkjIE5AoHJwgavmiv8PY=
      
// Bob现在可以将这个加密消息发送给Alice,而不用担心其他人能够读取原始内容
    
// Alice接收加密消息并使用她的私钥解密数据,恢复原始消息
let originalDecryptedMessage = try alicesPrivateKey.decrypt(privateMessage)
    
print(String(data: Data(originalDecryptedMessage), encoding: .utf8))
// "Hi Alice! This is Bob!"

RSA签名和验证示例

// Alice生成一个私钥
let alicesPrivateKey = try RSA(keySize: 1024)
    
// Alice想要签署一条她同意的消息
let messageAliceSupports = "Hi my name is Alice!"
let alicesSignature = try alicesPrivateKey.sign(messageAliceSupports.bytes)
    
// Alice与Bob分享她的公钥和签名
let alicesPublicKeyData = try alicesPrivateKey.publicKeyExternalRepresentation()
    
// Bob接收Alice公钥的原始外部表示并导入它!
let bobsImportOfAlicesPublicKey = try RSA(rawRepresentation: alicesPublicKeyData)
        
// Bob现在可以验证Alice使用与她共享的公钥相关联的私钥签署了该消息。
let verifiedSignature = try bobsImportOfAlicesPublicKey.verify(signature: alicesSignature, for: "Hi my name is Alice!".bytes)
    
if verifiedSignature == true {
  // Bob知道Alice提供的签名对该消息是有效的,并且是使用与Alice共享的公钥相关联的私钥签署的。
} else {
  // 签名无效,所以要么
  // - Alice签署的消息与我们预期的不同。
  // - 或者Alice使用了与Bob拥有的共享公钥不相关联的私钥。
}

CryptoSwift RSA密钥 -> Apple的Security Framework SecKey示例

/// 从CryptoSwift RSA密钥开始
let rsaKey = try RSA(keySize: 1024)

/// 定义你的密钥属性
let attributes: [String:Any] = [
  kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
  kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, // 或 kSecAttrKeyClassPublic
  kSecAttrKeySizeInBits as String: 1024, // 适当的位数
  kSecAttrIsPermanent as String: false
]
var error:Unmanaged<CFError>? = nil
guard let rsaSecKey = try SecKeyCreateWithData(rsaKey.externalRepresentation() as CFData, attributes as CFDictionary, &error) else {
  /// 从原始密钥数据构造SecKey时出错
  return
}

/// 现在你有了一个可以在Apple的Security框架中使用的RSA SecKey

Apple的Security Framework SecKey -> CryptoSwift RSA密钥示例

/// 从SecKey RSA密钥开始
let rsaSecKey:SecKey

/// 复制外部表示
var externalRepError:Unmanaged<CFError>?
guard let cfdata = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) else {
  /// 无法复制RSA SecKey的外部表示
  return
}

/// 从原始外部表示实例化RSA密钥
let rsaKey = try RSA(rawRepresentation: cfdata as Data)

/// 现在你有了一个CryptoSwift RSA密钥

作者

CryptoSwift由Marcin Krzyżanowski拥有和维护

你可以在Twitter上关注我 @krzyzanowskim 以获取项目更新和发布信息。

密码学通知

本发行版包含加密软件。你目前居住的国家可能对加密软件的进口、拥有、使用和/或再出口到另一个国家有限制。在使用任何加密软件之前,请检查你所在国家的法律、法规和政策,了解是否允许进口、拥有或使用加密软件,以及是否允许将其再出口。详情请参见 https://www.wassenaar.org/。

许可证

版权所有 (C) 2014-2022 Marcin Krzyżanowski marcin@krzyzanowskim.com 本软件按"原样"提供,不提供任何明示或暗示的保证。

在任何情况下,作者均不对因使用本软件而产生的任何损害承担责任。

允许任何人出于任何目的使用本软件,包括商业应用,并且可以自由更改和重新分发,但须遵守以下限制:

  • 不得歪曲本软件的来源;你不得声称你编写了原始软件。如果你在产品中使用本软件,产品文档中需要致谢
  • 更改后的源版本必须明确标明为such,不得歪曲为原始软件。
  • 本通知不得从任何源代码或二进制分发中删除或更改。
  • 任何形式的再分发都必须保留以下致谢:"本产品包含由"Marcin Krzyzanowski"(https://krzyzanowskim.com/)开发的软件。"

更新日志

请参阅CHANGELOG文件。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号