Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSA encryption/decryption implementing in Swift from Android Java code

I have these methods from Java that I need to implement in Swift:

    fun encryptMessage(content: String): String {
        val cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING")
        cipher.init(Cipher.ENCRYPT_MODE, publicKey)
        val encryptedBytes = cipher.doFinal(content.toByteArray())
        val encryptedData = Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
        return ENCRYPT_MARK + encryptedData
    }
​
    fun decryptMessage(content: String): String {
        val cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING")
        cipher.init(Cipher.DECRYPT_MODE, privateKey)
        var encryptedData = Base64.decode(content.substring(ENCRYPT_MARK.length), Base64.DEFAULT)
        val decryptedBytes = cipher.doFinal(encryptedData)
        return String(decryptedBytes)
    }

I am not very good in encryption and decryption. I tried several libraries and codes I found but nothing worked for me.

Example string that I need to decrypt:

"p+KuB7UVUteY8g3HVMxo+7h2xhZQxhPjPayMolqq8EYyIknbQjgqHjC95NR8/le6G0F8SQACrOdj\nTlPU1+o7bZrE8ukI7B35i9sWZns3Y2scA9U7yz8z5KsTZ240+4+Xd7dZwfQ49Z6J7nNOfBR/97pq\n2l1QKe0/SThUEraZyts=\n"

My private key:

"-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQDjOUZOZgIYWDMkyhyNb/gsFUDbDB3a+FWwT0d2HE7cd3bqebYLg\nKAMqwpc8nCHR77kO23Nd/U5WKVWwFcHUQVtkMcX4QNDtxSV72LRNaSaQZkwBofw9O\nu338mm1hR0DEYzYPXKuyaP3l5/pvZyvOHrA+i0ZD7pUohEtiDsuNhZbwIDAQABAoG\nBAJoM6q2cWy9GHOaEYHdDwm2guyfHPzaFxxKRrVFWP+EY3XZ6rgF+YwQzsgLyG3ic\nG7+AyyDSg18tymrWXCqJs7Mdrxq3xZmdCzwTcfgxZcwiFG0caK/jbA8rXO60xecag\nZRR+AyWa+2wnwt5xPtFcqk7GhqkWIolzQddW7L3CIuBAkEA9Xw+fnLrbR3WaxTpa3\n88NEEgvyxIS2eGc+lRUbC8w2xX5qDtV8Ak7rxkmXGURJ6tvwyUi/Q+5y+X20mBtt8\nsKwJBAOz0yph9n4iHtC+BL5U+LfpZuUO6uUctbmfXs+fU2glI8rAwXhanBCs0Ph/0\nG7aXmNKHvcSjQ9N5mhTPBvhpcc0CQH4PPTBF5ytzZQY8CNmQzuOuhhhlrwI5uUuQh\npfCgEyCOGlQPlEPdGe8CpTZRGAwc9xlo2pzFFI3mG2dQ6Ua2V0CQQCSMY11e7wbzi\n37SScEWzKezRCimueI5JzDcK/MjuRe6iThU1YZf73wsfDKYh9fDjT5X0pTsa89ID9\nSK1DPnq7ZAkB6ybvpomovyBBgSjjTEwwSHyAIr5HIE2hkDjer6/87/WNKEw1yg11b\ngSoJC67f1xnLj7bv9/EJRPWTokCaRRm/\n-----END RSA PRIVATE KEY-----"

1. SecKeyCreateDecryptedData

let encryptedMessageData = encryptedMessage.data(using: .utf8)
if let decryptedMessage:Data = SecKeyCreateDecryptedData(privateSecKey!, .rsaEncryptionPKCS1, encryptedMessageData as CFData, error) as Data? {
    print("We have an decrypted message \(String.init(data: decryptedMessage, encoding: .utf8)!)")
} else {
    print("Error decrypting")
}
  • not working. I get print "Error decrypting" but no error in variable

2. SwiftyRSA

    let encrypted = try EncryptedMessage(data: key.data(using: .utf8)!) // try EncryptedMessage(base64Encoded: key)
    
    let privateKey = try PrivateKey(pemEncoded: keyPair.privateKey)
    let decryptedKey = try encrypted.decrypted(with: privateKey, padding: SecPadding.PKCS1)
  • getting chunkDecryptFailed(index: 0) error.

3. CryptorRSA

    let data = base64.data(using: .utf8)!
    let encryptedData = try CryptorRSA.createEncrypted(with: data)
    let decryptedData = try encryptedData.decrypted(with: privateKey, algorithm: .sha1)
  • getting error:

    Error Domain=NSOSStatusErrorDomain Code=-50 "RSAdecrypt wrong input (err -27)" UserInfo={numberOfErrorsDeep=0, NSDescription=RSAdecrypt wrong input (err -27)}

I even try to implement decrypt with these lines of code but without luck:

static func decrypt(string: String, privateKey: String?) -> String? {
    guard let privateKey = privateKey else { return nil }
    
    let keyString = privateKey.replacingOccurrences(of: "-----BEGIN RSA PRIVATE KEY-----\n", with: "").replacingOccurrences(of: "\n-----END RSA PRIVATE KEY-----", with: "")
    guard let data = Data(base64Encoded: keyString, options: .ignoreUnknownCharacters) else { return nil }
    
    var attributes: CFDictionary {
        return [kSecAttrKeyType         : kSecAttrKeyTypeRSA,
                kSecAttrKeyClass        : kSecAttrKeyClassPrivate,
                kSecAttrKeySizeInBits   : 2048,
                kSecReturnPersistentRef : true] as CFDictionary
    }
    
    var error: Unmanaged<CFError>? = nil
    guard let secKey = SecKeyCreateWithData(data as CFData, attributes, &error) else {
        print(error.debugDescription)
        return nil
    }
    return decrypt(string: string, privateKey: secKey)
}

static func decrypt(string: String, privateKey: SecKey) -> String?  {
    let buffer = [UInt8](string.utf8)
    
    let keySize = SecKeyGetBlockSize(privateKey)
    var messageDecrypted = [UInt8](repeating: 0, count: keySize)
    var messageDecryptedSize = keySize
    
    var status = SecKeyDecrypt(privateKey, SecPadding.PKCS1, buffer, buffer.count, &messageDecrypted, &messageDecryptedSize)
    
    if status != noErr {
        print("Decryption Error!")
        return nil
    }
    
    let result = String(bytes: messageDecrypted, encoding: .utf8)
    print(result)
    return result
}

What am I doing wrong? How can I decrypt that example data? Thanks for help

like image 857
Libor Zapletal Avatar asked Jun 14 '26 23:06

Libor Zapletal


1 Answers

Below you'll see a quick example of encryption and decryption using a randomly generated key. I've added bang operators for simplicity, but it might just show you how you can encrypt and decrypt data using RSA in Swift.

let attributes = [
    kSecAttrKeyType: kSecAttrKeyTypeRSA,
    kSecAttrKeySizeInBits: 2048,
    kSecAttrKeyClass: kSecAttrKeyClassPrivate
] as CFDictionary

var error: Unmanaged<CFError>?
let privateKey = SecKeyCreateRandomKey(attributes, &error)!
let publicKey = SecKeyCopyPublicKey(privateKey)!

let message = Data("Hello World".utf8)

let ciphertext = SecKeyCreateEncryptedData(publicKey, .rsaEncryptionPKCS1, message as CFData, &error)! as Data

print(ciphertext as NSData)

let plaintext = SecKeyCreateDecryptedData(privateKey, .rsaEncryptionPKCS1, ciphertext as CFData, &error)! as Data
print(String(data: plaintext, encoding: .utf8) ?? "Non UTF8")

Now, we can do the same thing using your key. Your key currently is in PEM format. You'll have to remove the header, footer and all newlines to convert it to DER, iOS is quite strict in what is possible. You can replace some of the lines above with below code.

let keyBytes = Data(base64Encoded: "<your DER encoded bytes>")! as CFData

var error: Unmanaged<CFError>?
let privateKey = SecKeyCreateWithData(keyBytes, attributes, &error)!
let publicKey = SecKeyCopyPublicKey(privateKey)!

So that leaves me just to tell you that your cipher text is messed up or the cipher text was created with a different public key than the public key that belongs to your private key. I'm guessing the first, as I see new lines in a base64 string...

Now, some important notes:

  • Do not ship your product with the private key you posted here. It's called a privatekey for a reason
  • RSA is getting outdated, which is especially visible in its key sizes. You should not use 1024 bits RSA keys, they're not safe. Switch to keys of at least 2048 bits
  • Encryption is done using the publickey, decryption is done using the privatekey (as shown in the example)
  • Encryption using RSA keys is limited; only small amounts of data can be encrypted or decrypted and RSA is slow. If you need to encrypt lots of data and need it to be as fast as possible, you might want to check out AES or ChaCha (though both of them are symmetric algorithms)

P.S. Your DER encoded string is:

MIICXQIBAAKBgQDjOUZOZgIYWDMkyhyNb/gsFUDbDB3a+FWwT0d2HE7cd3bqebYLgKAMqwpc8nCHR77kO23Nd/U5WKVWwFcHUQVtkMcX4QNDtxSV72LRNaSaQZkwBofw9Ou338mm1hR0DEYzYPXKuyaP3l5/pvZyvOHrA+i0ZD7pUohEtiDsuNhZbwIDAQABAoGBAJoM6q2cWy9GHOaEYHdDwm2guyfHPzaFxxKRrVFWP+EY3XZ6rgF+YwQzsgLyG3icG7+AyyDSg18tymrWXCqJs7Mdrxq3xZmdCzwTcfgxZcwiFG0caK/jbA8rXO60xecagZRR+AyWa+2wnwt5xPtFcqk7GhqkWIolzQddW7L3CIuBAkEA9Xw+fnLrbR3WaxTpa388NEEgvyxIS2eGc+lRUbC8w2xX5qDtV8Ak7rxkmXGURJ6tvwyUi/Q+5y+X20mBtt8sKwJBAOz0yph9n4iHtC+BL5U+LfpZuUO6uUctbmfXs+fU2glI8rAwXhanBCs0Ph/0G7aXmNKHvcSjQ9N5mhTPBvhpcc0CQH4PPTBF5ytzZQY8CNmQzuOuhhhlrwI5uUuQhpfCgEyCOGlQPlEPdGe8CpTZRGAwc9xlo2pzFFI3mG2dQ6Ua2V0CQQCSMY11e7wbzi37SScEWzKezRCimueI5JzDcK/MjuRe6iThU1YZf73wsfDKYh9fDjT5X0pTsa89ID9SK1DPnq7ZAkB6ybvpomovyBBgSjjTEwwSHyAIr5HIE2hkDjer6/87/WNKEw1yg11bgSoJC67f1xnLj7bv9/EJRPWTokCaRRm/"
like image 115
Bram Avatar answered Jun 17 '26 11:06

Bram