使用来自服务器的字符串公钥的 RSA 加密

Posted

技术标签:

【中文标题】使用来自服务器的字符串公钥的 RSA 加密【英文标题】:RSA Encryption With String Public Key From Server 【发布时间】:2019-06-09 14:07:43 【问题描述】:

我正在尝试使用 RSA 加密字符串密码。 但我正在使用的功能是生成公钥​​,它是 SecKey 数据类型,这不是我需要的,因为我从服务器响应中获取公钥作为 String 。 我使用了许多库,但也使用相同的库,生成公钥 SecKey。 下面的课程显示了我的意思 我想将函数 func encryptBase64(text: String, secKey: SecKey) -> String 更改为 func encryptBase64(text: String, publicKey: String) -> String

类 RSAWrapper private var publicKey : SecKey? private var privateKey : SecKey?

func generateKeyPair(keySize: UInt, privateTag: String, publicTag: String) -> Bool 

    self.publicKey = nil
    self.privateKey = nil


    if (keySize != 512 && keySize != 1024 && keySize != 2048) 
        // Failed
        print("Key size is wrong")
        return false
    
    let publicKeyParameters: [NSString: AnyObject] = [
        kSecAttrIsPermanent: true as AnyObject,
        kSecAttrApplicationTag: publicTag as AnyObject
    ]
    let privateKeyParameters: [NSString: AnyObject] = [
        kSecAttrIsPermanent: true as AnyObject,
        kSecAttrApplicationTag: publicTag as AnyObject
    ]
    let parameters: [String: AnyObject] = [
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecAttrKeySizeInBits as String: keySize as AnyObject,
        kSecPrivateKeyAttrs as String: privateKeyParameters as AnyObject,
        kSecPublicKeyAttrs as String: publicKeyParameters as AnyObject
    ];

    let status : OSStatus = SecKeyGeneratePair(parameters as CFDictionary, &(self.publicKey), &(self.privateKey))

    return (status == errSecSuccess && self.publicKey != nil && self.privateKey != nil)


func encrypt(text: String) -> [UInt8] 
    let plainBuffer = [UInt8](text.utf8)
    var cipherBufferSize : Int = Int(SecKeyGetBlockSize((self.publicKey!)))
    var cipherBuffer = [UInt8](repeating:0, count:Int(cipherBufferSize))

    // Encrypto  should less than key length
    let status = SecKeyEncrypt((self.publicKey)!, SecPadding.PKCS1, plainBuffer, plainBuffer.count, &cipherBuffer, &cipherBufferSize)
    if (status != errSecSuccess) 
        print("Failed Encryption")
    
    return cipherBuffer


func decprypt(encrpted: [UInt8]) -> String? 
    var plaintextBufferSize = Int(SecKeyGetBlockSize((self.privateKey)!))
    var plaintextBuffer = [UInt8](repeating:0, count:Int(plaintextBufferSize))

    let status = SecKeyDecrypt((self.privateKey)!, SecPadding.PKCS1, encrpted, plaintextBufferSize, &plaintextBuffer, &plaintextBufferSize)

    if (status != errSecSuccess) 
        print("Failed Decrypt")
        return nil
    
    return NSString(bytes: &plaintextBuffer, length: plaintextBufferSize, encoding: String.Encoding.utf8.rawValue)! as String



func encryptBase64(text: String, secKey: SecKey) -> String 
    let plainBuffer = [UInt8](text.utf8)
    var cipherBufferSize : Int = Int(SecKeyGetBlockSize((secKey)))
    var cipherBuffer = [UInt8](repeating:0, count:Int(cipherBufferSize))

    // Encrypto  should less than key length
    let status = SecKeyEncrypt((self.publicKey)!, SecPadding.PKCS1, plainBuffer, plainBuffer.count, &cipherBuffer, &cipherBufferSize)
    if (status != errSecSuccess) 
        print("Failed Encryption")
    

    let mudata = NSData(bytes: &cipherBuffer, length: cipherBufferSize)
    return mudata.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength64Characters)


func decpryptBase64(encrpted: String) -> String? 

    let data : NSData = NSData(base64Encoded: encrpted, options: .ignoreUnknownCharacters)!
    let count = data.length / MemoryLayout<UInt8>.size
    var array = [UInt8](repeating: 0, count: count)
    data.getBytes(&array, length:count * MemoryLayout<UInt8>.size)

    var plaintextBufferSize = Int(SecKeyGetBlockSize((self.privateKey)!))
    var plaintextBuffer = [UInt8](repeating:0, count:Int(plaintextBufferSize))

    let status = SecKeyDecrypt((self.privateKey)!, SecPadding.PKCS1, array, plaintextBufferSize, &plaintextBuffer, &plaintextBufferSize)

    if (status != errSecSuccess) 
        print("Failed Decrypt")
        return nil
    
    return NSString(bytes: &plaintextBuffer, length: plaintextBufferSize, encoding: String.Encoding.utf8.rawValue)! as String



func getPublicKey() -> SecKey? 
    return self.publicKey


func getPrivateKey() -> SecKey? 
    return self.privateKey

【问题讨论】:

【参考方案1】:

关键概念是:

作为密钥对的服务器

公钥 私钥

应用程序也是密钥对

公钥 私钥

所以服务器应该知道应用程序的公钥,而应用程序应该知道服务器的公钥。

当服务器想要加密某些负载到应用程序时,服务器会与应用程序公开加密并将其发送到应用程序。应用使用应用私钥解密负载。

当应用想要加密某些负载到服务器时,应用会使用服务器公钥加密并将其发送到服务器。服务器使用服务器私钥解密负载。

这就是密钥对通信的工作方式。

在您的情况下,您应该只需要知道服务器公钥,因为您只需将内容发送到服务器,而无需生成应用密钥对。

Check this link 以便使用服务器公钥加密。

【讨论】:

以上是关于使用来自服务器的字符串公钥的 RSA 加密的主要内容,如果未能解决你的问题,请参考以下文章

RSA:在 iOS 中加密,在 Java 中解密

如何实现用javascript实现rsa加解密

C# RSA 加密/解密与传输

RSA Java 加密和 Node.js 解密不起作用

Android使用RSA加密和解密

rsa加密前后端不一致