Swift RSA 加签验签

Mac 终端生成密钥

  • 生成私钥
openssl genrsa -out rsa_private_key.pem 2048
  • 生成公钥
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
  • 生成证书
openssl req -new -key rsa_private_key.pem -out certificate.csr

生成的密钥字符串

struct RSAKey {
    static let privateKey = """
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEAtxt4MWNQdHp3FE03wHNoyAV63vvuOG47ToObtu9Z2ik6KQ1I
    rDfjOIjmD9P6F132Bw2VnkTy+zAXelnSYMiRcagTsXlGcI7SyG8dwc3aU12fgph0
    dBL5wIGWDVMqw6RJsEUYoV1ueaUCPiKr1jQGQpJ8Jlg04mj6glWx4G3mkvOc3nSq
    u915SANdR1BCgvJDhtRi4onLQcAUvRJOe8cEHhlAX6z45R8/yfkP9OMENAlchkQr
    2LUr3I7FSUl9q3pCFVmlRiML+IPySj3cqA6+8Gz2ZST8+8HfLCkcDC9e8AMZcJEx
    5sm0wk0TdFtl9o7SGAFcMR9CG9zWji7Z4SlA3QIDAQABAoIBAQCJ+JLadAEdo2Gy
    1HRb+RpNDYQGHULlFnptsNFWSIgl0MbYRAAsdHgsE0t3Rby+erh1nBDPDxkfmJ84
    PBI/hyHAyGr+YWloStYc3U1IyTnnczZMC2BETkAOhBZyt+YTQOmdfpMOk/44ftNv
    ymQ8pTrKUuJlajV/HKcWKkg72dPRiaPC/tCANZQLNjgylQUu3u1wEiCixBa+4lkO
    Uccldxy+7P9dzFTZJH/rBqxPCgHhajpSoBnFZJAC22Wk81QvRPS/JfbBG7wdxI7+
    iuxuH69bKHrZHPAxGpn0LqfsNvgJ5G/2jwyy/GkZDpNYsgjnKcAgyCsOCTNppO+J
    f5Ly6ljBAoGBAOmZmdeMkBxVPYOiKi37zJXwutvhKEos3I/jbTcaFnXaFpvP88vb
    XXnsy4bgFQ6Pm61ZMyguYO/Hn6LYjddDmM7C2yzWBIMFVnXMiTVtNUoXTbIH/8CC
    +Mz4O5ztITe1AU0D+aUzULGLjKv6LhEAAUYRAyrhR0y+BKNQYFyoHTRVAoGBAMiq
    YHEgvAqxlkDIh2hAVQce2PYTI0RJwBIPmK71H5j3JGZmda0JILqzLw176gV3k0Uq
    6wX65fD/psB683INy9fZ7fMGgbsnswDdqdBAUBdtPgzQO6fgEZ83S1FCKuceqHT5
    Wuj/hxeRvoE2+/tIYqWyM18oppFEoJxCF99izaJpAoGAFl+s2XVQFDah1qrAiXj1
    hmLxMsAlAL29PlbVDhMElbMWuUO4oQzYriXc9IUf3y4oBflmKfIPPMgM5ScCptyF
    lUAah/fTpMztFAlMFv7nvLnwqh2UBFdHBzK7WvNnXBONFVhNH+KDVw37ojkrElvC
    w3g7qm67SoFkplO7dwRvD6UCgYBux0A+s+ebr7ZXRV0bfIh0Sd9U2fPaOyzBy8Jq
    tAAhni6GKYJFaIidCVashwAGzKCMysi8oGpYxYn1MOs8x8kE/NaUF79+5se3bqfU
    w+xzQmfDAyIr51NTJl96GKE+vnoZOZ+qiYa2yEr3YrdxXeC3wM0Dd5mdENnp6cLs
    G8uSIQKBgEGR6KtnB2OOJObRfOCO3+asXoPP4kr4WnFeahvNOsKA+6FCYxljYX3J
    JemPi6eaZmIlXMqSgPjPjGNRv7vZbiCaROFdzXrgZbGuN7P2GLDI5Oq0fsfktd3y
    adXgXI4TPZ7/hw0o9Rpl63eIfaTxcCJM19VsNCWHdccF6LxTCewS
    -----END RSA PRIVATE KEY-----
    """

    static let publicKey = """
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtxt4MWNQdHp3FE03wHNo
    yAV63vvuOG47ToObtu9Z2ik6KQ1IrDfjOIjmD9P6F132Bw2VnkTy+zAXelnSYMiR
    cagTsXlGcI7SyG8dwc3aU12fgph0dBL5wIGWDVMqw6RJsEUYoV1ueaUCPiKr1jQG
    QpJ8Jlg04mj6glWx4G3mkvOc3nSqu915SANdR1BCgvJDhtRi4onLQcAUvRJOe8cE
    HhlAX6z45R8/yfkP9OMENAlchkQr2LUr3I7FSUl9q3pCFVmlRiML+IPySj3cqA6+
    8Gz2ZST8+8HfLCkcDC9e8AMZcJEx5sm0wk0TdFtl9o7SGAFcMR9CG9zWji7Z4SlA
    3QIDAQAB
    -----END PUBLIC KEY-----
    """
}

RSAKey 结构体用来存储已经生成的私钥和公钥

通过密钥字符串生成 SecKey,加签,验签

  • 详细代码
import Foundation

/// 密钥类型
enum KeyType {
    case publicKey
    case privateKey
}

struct RSASigner {

    /// 通过密钥字符串获取 SecKey 类型的密钥
    /// - Parameter keyString: 密钥字符串
    /// - Parameter keyType: 密钥类型
    static func getSecKey(with keyString: String,keyType: KeyType) -> SecKey? {
        let strippedKey = String(keyString.filter { !" \n\t\r".contains($0) })

        let pemComponents = strippedKey.components(separatedBy: "-----")

        guard pemComponents.count >= 5 else { return nil }

        guard let keyData = Data(base64Encoded: pemComponents[2]) else { return nil }

        let keyClass = keyType == .publicKey ? kSecAttrKeyClassPublic : kSecAttrKeyClassPrivate
        let sizeInBits = keyData.count * MemoryLayout<UInt8>.size
        let keyDict: [CFString: Any] = [
            kSecAttrKeyType: kSecAttrKeyTypeRSA,
            kSecAttrKeyClass: keyClass,
            kSecAttrKeySizeInBits: NSNumber(value: sizeInBits)
        ]

        guard let key = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, nil) else { return nil }

        return key
    }


    /// 使用 RSA 算法签名
    /// - Parameter text: 明文
    /// - Parameter privateKey: 密钥
    static func sign(text: String, with privateKey: SecKey) -> String? {
        guard let data = text.data(using: .utf8) else { return nil }

        guard let signedData = SecKeyCreateSignature(privateKey, .rsaSignatureMessagePKCS1v15SHA256, data as CFData , nil) as Data? else { return nil }

        return signedData.base64EncodedString()
    }


    /// 验证签名
    /// - Parameter signature: 签名字符串
    /// - Parameter text: 明文
    /// - Parameter publicKey: 公钥
    static func verify(signature: String, text: String, with publicKey: SecKey) -> Bool {
        guard let signedData = text.data(using: .utf8) else { return false }

        guard let signature = Data(base64Encoded: signature) else {  return false }

        return SecKeyVerifySignature(publicKey, .rsaSignatureMessagePKCS1v15SHA256, signedData  as CFData, signature as CFData,nil)
    }
}

上面的代码可以通过 RSA 私钥字符串或公钥字符串(如上面所示)生成 Swift 中需要的 SecKey 类型的密钥。使用 SecKey 类型的私钥字符串用来加签,使用 SecKey 类型的公钥用来验签。

定义了一个枚举类型 KeyType 用来标识要生成的是私钥(publicKey)还是公钥(privateKey

使用 getSecKey(with,keyType)方法来获取 SecKey 类型的密钥

使用 sign(text: with:) 方法类生成签名

使用 verify(signature: text: with) 来验证签名是否正确

  • 使用示例
func testSignAndVerify() {
    let text = "我是明文"
    guard let privateKey =  RSASigner.getSecKey(with: RSAKey.privateKey, keyType: .privateKey) else {
        return
    }
    guard let signature = RSASigner.sign(text: text, with: privateKey) else {
        return
    }
    guard let pubKey = RSASigner.getSecKey(with: RSAKey.publicKey, keyType: .publicKey) else {
        return
    }
    let result = RSASigner.verify(signature: signature, text: text, with: pubKey)
    print("明文:\(text)")
    print("签名:\(signature)")
    print("验签\(result ? "成功" : "失败")")
}
  • 打印结果
明文:我是明文
签名:tD2TjObA/NBRfHjbd3wT4KyAuo+yMWiIXJHVA3qOYMP4ow/WJKzrtaSVQT/COt3ZNMhYY1MTn5syemJ3tcAcFvJtIyprN+rnJMLR9Yu8rrh5yfOa/t55pMsedobUt3ER7SCI5oosyVtvO0EojDK5SG1OFuT9GgfbnSNoFkf2blK7bnuEiLvnlSw/TukKusqeX2OiatvL1qtE3Z0b9RKZRaFl99o/pVo+D5vNGG+K5A9dt6vG/gI0OZYR9YZHT1GIOAryFBejRDeuqP3vniQL0AJRjYXr+cZ4LkiFV1w8X61+Qz6udD6pjeYou3kBwKJOF08mcu+ot9DIh508dQfUtw==
验签成功
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容

  • 原文地址 https://mbinary.coding.me/introduction-to-bitcoin.ht...
    mbinary阅读 5,055评论 0 4
  • 数字证书原理 - 无恙 - 博客园 文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明...
    拉肚阅读 1,654评论 0 3
  • 前言 文中首先解释加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的...
    sunny冲哥阅读 2,964评论 0 2
  • 文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现...
    sunny冲哥阅读 1,357评论 0 3
  • 钱包 - 比特币开发指南 原文链接: https://bitcoin.org/en/developer-guide...
    terryc007阅读 2,878评论 0 7