RSA public/private key encryption in Swift

Overview

SwiftyRSA

Maintainer(s): @ikeith

Public key RSA encryption in Swift.

SwiftyRSA is used in the Scoop iOS app to encrypt driver license numbers before submitting them to Checkr through our API.

Installation

Swift 5.0+

SwiftyRSA uses Swift 5.0 and requires Xcode 10.2+.

With Cocoapods:

pod 'SwiftyRSA'

With Carthage:

github "TakeScoop/SwiftyRSA"

Objective-C

pod 'SwiftyRSA/ObjC'

Quick Start

Encrypt with a public key

let publicKey = try PublicKey(pemNamed: "public")
let clear = try ClearMessage(string: "Clear Text", using: .utf8)
let encrypted = try clear.encrypted(with: publicKey, padding: .PKCS1)

// Then you can use:
let data = encrypted.data
let base64String = encrypted.base64String

Decrypt with a private key

let privateKey = try PrivateKey(pemNamed: "private")
let encrypted = try EncryptedMessage(base64Encoded: "AAA===")
let clear = try encrypted.decrypted(with: privateKey, padding: .PKCS1)

// Then you can use:
let data = clear.data
let base64String = clear.base64String
let string = clear.string(using: .utf8)

Advanced Usage

Create a public/private key representation

With a DER file

let publicKey = try PublicKey(derNamed: "public")
let privateKey = try PrivateKey(derNamed: "private")

With a PEM file

let publicKey = try PublicKey(pemNamed: "public")
let privateKey = try PrivateKey(pemNamed: "private")

With a PEM string

let publicKey = try PublicKey(pemEncoded: str)
let privateKey = try PrivateKey(pemEncoded: str)

With a Base64 string

let publicKey = try PublicKey(base64Encoded: base64String)
let privateKey = try PrivateKey(base64Encoded: base64String)

With data

let publicKey = try PublicKey(data: data)
let privateKey = try PrivateKey(data: data)

With a SecKey

let publicKey = try PublicKey(reference: secKey)
let privateKey = try PrivateKey(reference: secKey)

Encrypt with a public key

let str = "Clear Text"
let clear = try ClearMessage(string: str, using: .utf8)
let encrypted = try clear.encrypted(with: publicKey, padding: .PKCS1)

let data = encrypted.data
let base64String = encrypted.base64Encoded

Decrypt with a private key

let encrypted = try EncryptedMessage(base64Encoded: base64String)
let clear = try encrypted.decrypted(with: privateKey, padding: .PKCS1)

let data = clear.data
let base64String = clear.base64Encoded
let string = try clear.string(using: .utf8)

Sign with a private key

SwiftyRSA can sign data with a private key. SwiftyRSA will calculate a SHA digest of the supplied String/Data and use this to generate the digital signature.

let clear = try ClearMessage(string: "Clear Text", using: .utf8)
let signature = clear.signed(with: privateKey, digestType: .sha1)

let data = signature.data
let base64String = signature.base64String

Verify with a public key

SwiftyRSA can verify digital signatures with a public key. SwiftyRSA will calculate a digest of the supplied String/Data and use this to verify the digital signature.

let signature = try Signature(base64Encoded: "AAA===")
let isSuccessful = try clear.verify(with: publicKey, signature: signature, digestType: .sha1)

Create a public/private RSA key pair

let keyPair = SwiftyRSA.generateRSAKeyPair(sizeInBits: 2048)
let privateKey = keyPair.privateKey
let publicKey = keyPair.publicKey

Export a key or access its content

let pem = try key.pemString()
let base64 = try key.base64String()
let data = try key.data()
let reference = key.reference
let originalData = key.originalData

Use X.509 certificate

SwiftyRSA supports X.509 certificate for public keys. SwiftyRSA can add the X.509 header to a headerless public key, or on the contrary strip it to get a key without a header.

Add an X.509 header to a public key

let publicKey = PublicKey(data: data)
let publicKeyData = try publicKey.data()
let publicKey_with_X509_header = try SwiftyRSA.prependX509KeyHeader(keyData: publicKeyData)

Strip the X.509 header from a public key

let publicKey_headerLess: Data = try SwiftyRSA.stripKeyHeader(keyData: publicKey_with_X509_header)

Warning : Storing (with SwiftyRSA's methods) or creating a PublicKey instance will automatically strip the header from the key. For more info, see Under the hood above.

Create public and private RSA keys

Use ssh-keygen to generate a PEM public key and a PEM private key. SwiftyRSA also supports DER public keys.

$ ssh-keygen -t rsa -f ~/mykey -N ''
$ cat ~/mykey > ~/private.pem
$ ssh-keygen -f ~/mykey.pub -e -m pem > ~/public.pem

Your keys are now in ~/public.pem and ~/private.pem. Don't forget to move ~/mykey and ~/mykey.pub to a secure place.

Under the hood

To enable using public/private RSA keys on iOS, SwiftyRSA uses a couple techniques like X.509 header stripping so that the keychain accepts them.

Click here for more details

When encrypting using a public key:

  • If the key is in PEM format, get rid of its meta data and convert it to Data
  • Strip the public key X.509 header, otherwise the keychain won't accept it
  • Add the public key to the keychain, with a random tag
  • Get a reference on the key using the key tag
  • Use SecKeyEncrypt to encrypt a ClearMessage using the key reference and the message data.
  • Store the resulting encrypted data to an EncryptedMessage
  • When the key gets deallocated, delete the public key from the keychain using its tag

When decrypting using a private key:

  • Get rid of PEM meta data and convert to Data
  • Add the private key to the app keychain, with a random tag
  • Get a reference on the key using the key tag
  • Use SecKeyDecrypt to decrypt an EncryptedMessage using the key reference and the encrypted message data
  • Store the resulting decrypted data to a ClearMessage
  • Delete private key from keychain using tag

Inspired from

License

This project is copyrighted under the MIT license. Complete license can be found here: https://github.com/TakeScoop/SwiftyRSA/blob/master/LICENSE

Comments
  • RSA private key creation from data failed code=-50

    RSA private key creation from data failed code=-50

    I am currently trying to create a PrivateKey from a base64 encoded key via base64Encoded and pemEncoded. Since I always received the Couldn't create key reference from key data SwiftyRSAError, I decided to check for more meaningful errors and found that no matter the key I pass in, I always get the error listed in the title.

    The change to see this error is found in SwiftyRSA.addKey within the iOS 10.0 if block.

    Change guard let key = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, nil) to

    var error:Unmanaged<CFError>? = nil
    guard let key = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, &error) else {
      print(error)
    ...
    }
    

    I have tested this with about 20 different RSA private keys as well as those found in the test key folder. I am not sure if I am going on the wrong track or not.

    opened by rdadkins 23
  • Add support for generating and verifying digital signatures

    Add support for generating and verifying digital signatures

    At present the signing function throws an exception if you try and sign too much data. Ideally the function would generate an SHA1 digest of the data and sign that, but integration of CommonCrypto into Swift frameworks seems to be tricky. See - http://iosdeveloperzone.com/2014/10/03/using-commoncrypto-in-swift/

    opened by paulw11 19
  • Signature verification fails

    Signature verification fails

    Hello,

    I have been using your library in production for the past 6 months or so, but after upgrading to Swift 3, I can no longer verify signatures for messages signed on our CentOS server. I am using the exact same server-side script & keys to sign the messages as I did before upgrading to Swift 3.

    Here is how the server keys were generated:

    ssh-keygen -t rsa -f serverkey -N '' -b 2048
    mv serverkey serverkey-priv.pem
    ssh-keygen -f serverkey.pub -e -m pem > serverkey-pub.pem ; rm -f serverkey.pub
    
    

    I sign the message like this: cat message | openssl dgst -sha256 -sign serverkey-priv.pem -out signature.bin

    Then I base64-encode signature.bin and send the message along with the base64-encoded signature to the iOS device where I try to verify the signature like this: set verificationResult = SwiftyRSA.verifySignatureString(stringToVerify, signature: signature, publicKeyPEM: serverKey, digestMethod: .SHA256)

    The problem is that verificationResult.isSuccessful returns false. The error property is:

    Error Domain=com.takescoop.SwiftyRSA Code=500 "Couldn't decode PEM key data (base64)" UserInfo={NSLocalizedDescription=Couldn't decode PEM key data (base64)}

    Here is the message: Raw message, 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ, very sensitive information!!

    The signature (base64-encoded hash): p9+ID34iW9+ff+2S25GY0fViWzdQgCwZIwFRZAPEk6/onODvmq3wa1471btGuez+0dtUZ3f2z3Mii7x0mmPcn0cZEvjFWVQrI0+woDd3/hcOkpIdYUHAQmaRVOARx5PZgHF0LosPf6aP1ePhHUmrJHwyTmfok+tjcZwtCaeJCQYaSFqTE3F6c78guMEaq83vg/zsBBceBlAhQSCZb3lhIJZqu8Y2AHyDpuCfrANURx8XkYwcxu5ark+/YGIdkNqrrkeg5X2daph+Qfefn8ikq/kL9wTnleJ9miKDKQVc5YqKhwhhv5Y6nZ86wVeS9+uv/Yz6HS7wwxbwRJJ28w28ZQ==

    Attached is a zip file with the actual message, hash and key pair used.

    message-hash-and-key.zip

    Help with this would be much appreciated!

    opened by Laban1 18
  • Added ‘generateRSAKeyPair’ to SwiftyRSA enum.

    Added ‘generateRSAKeyPair’ to SwiftyRSA enum.

    The method was added together with an accompanying test, although the test will fail due to what is believed to be a unit test bug http://www.openradar.me/36809637

    Apologies for any formatting I've messed up slightly, my Xcode prefs are slightly different.

    Let me know if any changes are needed 👍

    Signed-off-by: Christoffer Buusmann [email protected]

    opened by foffer 16
  • Support Swift Package Manager

    Support Swift Package Manager

    Very simple support for SPM, just a new library product for SwiftyRSA. There are ways to cheese Obj-C code into a package, but migrating the single Objective-C class seemed more straightforward. Tested with Xcode 11.7 and 12.0.1

    opened by bednarj4 15
  • Swift 5.2 ClearMessage Has Bad Encryption

    Swift 5.2 ClearMessage Has Bad Encryption

    After update swift version to 5.2 and update build latest "SwiftyRSA", encryption method at "ClearMessage" class sometime has wrong data.

    Test : I saved a clear message when encryption was OK, and for next time used from that object again BUT! for second time encrypted data was not ok. in fact correct encrypted data completely is random after update to swift 5.2.

    func generateEncryptedSymmetricKeyData(length :Int,secondaryChunkSize:Int) -> Data {
    // TEST AGAIN: repeat 'encrypted' method when encryption was ok
            if isOk { 
                do {
                    encryptedSymmetricKeyData = Data()
                    for clear in safeClearMessage {
                        let encrypted = try clear.encrypted(with: publicKeyClient, padding: .PKCS1)
                        encryptedSymmetricKeyData.append(contentsOf: encrypted.data)
                    }
                    return encryptedSymmetricKeyData
                } catch  {
                    print(error)
                }
            }
      //===================================================================
    
    
            encryptedSymmetricKeyData = Data()
            symmetricKey = IGGlobal.randomString(length: length)
            do {
                let symmetricKeyData = symmetricKey.data(using: .utf8)
                var encSymmetricKeyData = try encrypt(rawData: symmetricKeyData!) 
                let publicKey = try PublicKey(pemEncoded: embeddedPublicKey)
                publicKeyClient = publicKey
                while(0<encSymmetricKeyData.count){
                    let chunk = encSymmetricKeyData.subdata(in: 0..<secondaryChunkSize)
                    let clear = ClearMessage(data: chunk)
    
                    // STORE: store "ClearMessage" Object for use next time
                    safeClearMessage.append(clear)
    
                   // **ERROR LINE** this line sometimes is OK and sometimes is NOT OK
                   let encrypted = try clear.encrypted(with: publicKey, padding: .PKCS1)
    
    
                    encryptedSymmetricKeyData.append(contentsOf: encrypted.data)
                    encSymmetricKeyData = encSymmetricKeyData.subdata(in: secondaryChunkSize..<encSymmetricKeyData.count)
                }
            } catch  {
                print(error)
            }
            return encryptedSymmetricKeyData
        }
    
    opened by saeedmozaffari 14
  • Generating RSA key pair on iOS

    Generating RSA key pair on iOS

    Thanks for writing this useful library!

    Can this library be used to generate an RSA key pair on the iOS device (as opposed to generating the keys on a server)? If not, any suggestion on another library that will generate PEM keys that are compatible with this library?

    opened by Laban1 14
  • publicKeyFromPEMString error code 500

    publicKeyFromPEMString error code 500

    Hi @ldiqual, thanks for this library. Very cool. Is there an issue with the latest commit and publicKeyFromPEMString(pubString)?

    In my Swift playground, I found the following: privateKeyFromPEMString works. publicKeyFromDERData works. publicKeyFromPEMString fails.

    Example to show you the error:

    let rsa = SwiftyRSA() let pubPath: String = NSBundle.mainBundle().pathForResource("public", ofType: "pem")!

    if NSFileManager().fileExistsAtPath(pubPath) {
        do {
            let pubString = try NSString(contentsOfFile: pubPath, encoding: NSUTF8StringEncoding) as String
                        print(pubString)
           // let pubKey = try rsa.publicKeyFromPEMString(pubString)
    
        } catch let error as NSError {
            print(error.code)
            print(error.description)
        }
    }
    
    opened by rustymagnet3000 13
  • Bouncy Castle Encryption

    Bouncy Castle Encryption

    Hey, I am trying to integrate with an API which uses BouncyCastle encryption, so the server is not able to decrypt the data which i am encrypting using SwiftyRSA. Am i doing something wrong or it won't work because it is using Bouncy Castle?

    Kindly Help.

    opened by rsdev-darshan 11
  • Allow encryption of empty strings / data when padding is used

    Allow encryption of empty strings / data when padding is used

    We currently have a problem with using SwiftyRSA because a third party required encoded empty strings. When using padding like PKCS, it is allowed to encrypt empty strings according to the standard. I have enabled this in this pull request and added a test.

    However, I can't get the decrypt to work with Apple's SecKeyEncrypt. This returns status -9809 which means "An underlying cryptographic error was encountered.".

    Please comment on how to implement the decryption.

    opened by scspijker 9
  • Support of the X509 header for any public key

    Support of the X509 header for any public key

    This PR fixes the issue #81.

    It enables to prepend a X509 header to a headerless public key. The new method does the exact opposite of the native method stripKeyHeader()

    If the given key isn't headerless, it is returned as is.

    A part of the new code come from Heimdall's project released under MIT Licence.

    Header key can be verified on Lapo's online decoder by anyone.

    With the new method, all public keys are compatible with the most of javascript, java, python (etc...) rsa algorithms. It could fix some of the gihtub SwiftyRSA's issues

    opened by DevNathan 8
  • AAAAAAAAAAAAAAAAAAA =

    AAAAAAAAAAAAAAAAAAA =

    do { let publicKey = try PublicKey(pemNamed: "public")

    let str = "Clear String"
    let clear = try ClearMessage(string: str, using: .utf8)
    let encrypted = try clear.encrypted(with: publicKey, padding: .PKCS1)
    
    let data = encencrypted.data
    print(data)
    
    let base64String = encrypted.base64String
    print(base64String)
    

    } catch { print(error) }

    I use public key encryption, The result is "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA =" Good depressed, excuse me have a solution?

    opened by KALIANS 0
  • Add PSS padding and salt length parameters

    Add PSS padding and salt length parameters

    I'm interested using additional parameters for algorithm:

    1. Padding (PSS).
    2. Salt length.

    Now padding is PKCS1 by default and isn't configurable and no salt parameter at all. I found that in this library, for example.

    opened by vani2 0
  • SwiftyRSA.prependX509KeyHeader is internal

    SwiftyRSA.prependX509KeyHeader is internal

    On version 1.7.0 SwiftyRSA.prependX509KeyHeader is marked as internal. In your example it should work and should thus be public. Could this be changed please? Thanks, Jan

    opened by JanIceTea 0
Releases(0.2.1)
Owner
Scoop
Scoop
Util for generation RSA keys on your client and save to keychain or convert into Data 🔑 🔐

RSASwiftGenerator ?? ?? To run the example project, clone the repo, and run pod install from the Example directory first. Requirements ⚠️ SWIFT 4 XCod

null 21 Apr 30, 2022
Enigma encryption in Swift

?????????????????? ?????????? // Will create an Enigma with an empty plugboard, rotors I, II, III and reflector B (wide). let enigma = Enigma() // Wil

Joakim Gyllström 113 Dec 16, 2022
CCCryptor (AES encryption) wrappers for iOS and Mac in Swift. -- For ObjC, see RNCryptor/RNCryptor-objc

RNCryptor Cross-language AES Encryptor/Decryptor data format. The primary targets are Swift and Objective-C, but implementations are available in C, C

null 3.3k Jan 7, 2023
An easy way for hashing and encryption.

CatCrypto include a series of hashing and encryption functions and more functions in progress! CatCrypto also contains Swift bindings of Argon2, the p

Kcat 62 Sep 27, 2022
A wrapper for Apple's Common Crypto library written in Swift.

IDZSwiftCommonCrypto A Swift wrapper for Apple's CommonCrypto library. IDZSwiftCommonCrypto works with both CocoaPods and Cathage. For more details on

idz 472 Dec 12, 2022
Read my answer here Importing CommonCrypto in a Swift framework

Read my answer here Importing CommonCrypto in a Swift framework

Khoa 281 Sep 17, 2022
A pure Swift implementation of MD5

SwiftMD5 SwiftMD5 is a pure Swift implementation for the MD5 algorithm. Usage import SwiftMD5 "The quick brown fox jumps over the lazy dog".md5 // "9

Matthew Purland 11 Sep 25, 2021
🍕 MD5 in pure Swift

SwiftHash ❤️ Support my app ❤️ Push Hero - pure Swift native macOS application to test push notifications Quick Access - Organise files in the Mac men

Khoa 207 Dec 24, 2022
A tiny and easy to use Swift class to encrypt strings using HMAC algorithms.

#Sweet HMAC SweetHMAC is a tiny and easy to use Swift class to encrypt strings using HMAC algorithms. A special thanks to jernejstrasner for shared HM

Jan Cássio 37 Jul 27, 2022
CryptoSwift is a growing collection of standard and secure cryptographic algorithms implemented in Swift

CryptoSwift Crypto related functions and helpers for Swift implemented in Swift. (#PureSwift) Note: The main branch follows the latest currently relea

Marcin Krzyzanowski 9.4k Jan 9, 2023
Elegant Swift interface to access the CommonCrypto routines

SCrypto [Overview • Requirements • Installation • Usage • Alternatives • Licence] Overview SCrypto provides neat Swift interface to access the CommonC

Max 39 Mar 31, 2022
Simple and secure hashing in Swift with the SipHash algorithm

SipHash ⚠️ WARNING This package has been obsoleted by the Hasher type and the Hashable.hash(into:) requirement introduced in Swift 4.2. Using this pac

null 262 Dec 19, 2022
Virgil Crypto stack Objective-C/Swift

Virgil Crypto Library Objective-C/Swift Introduction | Library purposes | Installation | Usage examples | Docs | License | Contacts Introduction Virgi

Virgil Security, Inc. 31 Oct 12, 2022
A framework for the JOSE standards JWS, JWE, and JWK written in Swift.

JOSESwift is a modular and extensible framework for the JOSE standards JWS, JWE, and JWK written in Swift. ?? Please note that this implementation of

Airside Mobile, Inc. 162 Dec 15, 2022
RSA public/private key encryption, private key signing and public key verification in Swift using the Swift Package Manager. Works on iOS, macOS, and Linux (work in progress).

BlueRSA Swift cross-platform RSA wrapper library for RSA encryption and signing. Works on supported Apple platforms (using Security framework). Linux

Kitura 122 Dec 16, 2022
RSA public/private key generation, RSA, AES encryption/decryption, RSA sign/verify in Swift with CommonCrypto in iOS and OS X

SwCrypt Create public and private RSA keys in DER format let (privateKey, publicKey) = try! CC.RSA.generateKeyPair(2048) Convert them to PEM format l

soyer 695 Dec 8, 2022
RSA public/private key encryption in Swift

SwiftyRSA Maintainer(s): @ikeith Public key RSA encryption in Swift. SwiftyRSA is used in the Scoop iOS app to encrypt driver license numbers before s

Scoop 1.1k Jan 5, 2023
Swift RSA Key Loader

Swift RSA Key Loader Requirements iOS 9.0+ Installation See the subsections below for details about the different installation methods. Swift Package

Dmytrii Golovanov 1 Jun 13, 2022
This is the public repository of the MADBike app for iOS. Public bike rental service for BiciMAD.

MADBike Requirements iOS 10.3+ Xcode 10.3+ Swift 4+ Installation Copy BiciMAD/Supporting Files/GoogleService-Info-Sample.plist to BiciMAD/Supporting F

Alex Rupérez 24 Mar 25, 2022
RSA encrypt and decrypt in Swift

MZRSA_Swift MZRSA_Swift是一个轻量级框架,框架功能包含RSA加密/解密Data、RSA加密/解密String,支持字符串密钥和证书密钥 公钥加密&私钥解密(字符串密钥) 代码示例 let PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8

null 8 Jan 5, 2023