Could not decrypt a base64String using CryptoSwift - ios

String for encryption "secret"
after encryption "64c2VjcmV0"
this is the code that works properly
let inputNSData: NSData = input.dataUsingEncoding(NSUTF8StringEncoding)!
let inputBytes: [UInt8] = inputNSData.arrayOfBytes()
let key: [UInt8] = self.generateArray("secret0key000000") //16
let iv: [UInt8] = self.generateArray("0000000000000000") //16
do {
let encrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .CBC).encrypt(inputBytes, padding: PKCS7())
let decrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .CBC).decrypt(encrypted, padding: PKCS7())
let decryptNsData: NSData = NSData(bytes: decrypted, length: decrypted.count)
let c = decryptNsData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let decryptedString: String = NSString(data: decryptNsData, encoding: NSUTF8StringEncoding) as! String
print("String after decryption\t\(decryptedString)")
} catch {
// some error
}
but i could not decrypt by using the same key and iv
I am getting fatal error: unexpectedly found nil while unwrapping an Optional value for the encrypted string
let key: [UInt8] = self.generateArray("secret0key000000") //16
let iv: [UInt8] = self.generateArray("0000000000000000") //16
let input: String = "64c2VjcmV0"
var encryptedStrData = NSData(base64EncodedString: input, options: NSDataBase64DecodingOptions())!
let inputBytes: [UInt8] = encryptedStrData.arrayOfBytes()
print("String in uint8\(inputBytes)")
//var keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
//var ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
do{
let decryptedTryData = try AES(key: key, iv: iv, blockMode: .CBC).decrypt(inputBytes)
print(decryptedTryData)
}
catch{
}
I am getting fatal error: unexpectedly found nil while unwrapping an Optional value for the encrypted string

You are using Base64 when it is not necessary, only Base64 encode non string data.
Here is the first test code:
let inputBytes: [UInt8] = Array("secret".utf8)
let key: [UInt8] = Array("secret0key000000".utf8) //16
let iv: [UInt8] = Array("0000000000000000".utf8) //16
var encryptedBase64 = ""
do {
let encrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .CBC).encrypt(inputBytes, padding: PKCS7())
let encryptedNSData = NSData(bytes: encrypted, length: encrypted.count)
encryptedBase64 = encryptedNSData.base64EncodedStringWithOptions([])
let decrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .CBC).decrypt(encrypted, padding: PKCS7())
let result = String(bytes: decrypted, encoding: NSUTF8StringEncoding)!
print("result\t\(result )")
} catch {
// some error
}
print("encryptedBase64: \(encryptedBase64)")
Output:
result: secret
encryptedBase64: 0OCxa0yJszq9MvkrWjn3wg==
let encryptedData = NSData(base64EncodedString: encryptedBase64, options:[])!
print("decodedData: \(encryptedData)")
let encrypted = Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(encryptedData.bytes), count: encryptedData.length))
do {
let decryptedData = try AES(key: key, iv: iv, blockMode: .CBC).decrypt(encrypted)
let decryptedString = String(bytes: decryptedData, encoding: NSUTF8StringEncoding)!
print("decryptedString: \(decryptedString)")
}
catch{
// some error
}
Output:
decryptedString: secret
Notes:
Don't use CryptoSwift, it does not use the build-in encryption hardware and is 400 to 1000 times slower than the Apple Security.framework Common Crypto. It is also not well vetted and used non-certified encryption code.
Don't use a string directly as the key, it is not secure. Instead derive a key from the string using PBKDK2 (Password Based Key Derivation Function).

Base64 strings must be divisible by 4. Yours is not.
You can use a website, such as https://www.base64decode.org, to test your strings.

For Swift3 (to avoid the UnsafePointer error) this has worked for me for the second part (decoding the base64 variable):
let encryptedData = NSData(base64Encoded: encryptedBase64, options:[])!
print("decodedData: \(encryptedData)")
let count = encryptedData.length / MemoryLayout<UInt8>.size
// create an array of Uint8
var encrypted = [UInt8](repeating: 0, count: count)
// copy bytes into array
encryptedData.getBytes(&encrypted, length:count * MemoryLayout<UInt8>.size)
do {
let decryptedData = try AES(key: key, iv: iv, blockMode: .CBC).decrypt(encrypted)
let decryptedString = String(bytes: decryptedData, encoding: String.Encoding.utf8)!
print("decryptedString: \(decryptedString)")
}
catch{
// some error
}

Related

How to Decrypt a string using AES-256 CFB with PKCS5PADDING in swift?

I am looking to decrypt a string using AES, I tried multiple solution from SO but none of them helped and I was unable to get the solution. The android developer used Cipher to do it below is the code for that:-
private static final byte[] initVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
private static Cipher getAES_Cipher(int opmode) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException {
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(Arrays.copyOfRange(getSHA(key), 0, 32), "AES");
Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5PADDING");
cipher.init(opmode, skeySpec, iv);
return cipher;
}
Similarly I tried using CryptoSwift to do it and below is the code I used to do it:-
extension String {
func aesEncrypt(key: String, iv: String) throws -> String {
let data: Array<UInt8> = (self.data(using: .utf8)?.bytes)!
var key: Array<UInt8> = (key.data(using: .utf8)?.bytes)!
let iv: Array<UInt8> = (iv.data(using: .utf8)?.bytes)!
do {
let encrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).encrypt(data)
let encryptedData = Data(encrypted)
let decrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(encrypted)
let decryptedData = Data(decrypted)
let str = String.init(data: decryptedData, encoding: .utf8)
print(str ?? String())
return encryptedData.base64EncodedString()
} catch {
print(error)
return "error"
}
}
func aesDecrypt(key: String, iv: String) throws -> String {
let data: Array<UInt8> = (Data(base64Encoded: self)?.bytes)!
let key: Array<UInt8> = (key.data(using: .utf8)?.bytes)!
let iv: Array<UInt8> = (iv.data(using: .utf8)?.bytes)!
do {
let decrypted = try AES(key: key.sha256(), blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(data)
let decryptedData = Data(decrypted)
guard let value = String.init(data: decryptedData, encoding: .utf8) else {
return "error"
}
return value
} catch {
print(error)
return "error"
}
}
}
and In ViewDidLoad() I called it like this:-
let message = "My Encrypted String From The Server"
let test = try! message.aesDecrypt(key: "dfksjghlskjdfhglksjdfhglkjsdhfglkjhsfopweiurtypoweirutopiewrutgopiruegoijnsdeghsedrghesrerthigoererhehewthgewrhywertyweyweyewrtewrtyewihgoie", iv: "0000000000000000")
print(test)
One more thing I want to highlight when I pass the same iv as android which is "{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }" I am getting the error from the CryptoSwift library as invalidInitializationVector but when I pass iv: "0000000000000000" I am getting an error -->
guard let value = String.init(data: decryptedData, encoding: .utf8) else {
return "error"
}
I believe it is something related to the iv that I am passing there.
Guys any help would be greatly appreciated!!
Thank You
Found that question when tried to decode some data using CryptoSwift. Tried the code and it didn't work for me too (did return "error").
The issue is in decrypt method and is related to key.
You have for encryption:
let encrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).encrypt(data)
But to decryption the code looks like this:
let decrypted = try AES(key: key.sha256(), blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(data)
For me removing .sha256() fixed the issue.
So final decrypt method should be:
func aesDecrypt(key: String, iv: String) throws -> String {
let data: Array<UInt8> = (Data(base64Encoded: self)?.bytes)!
let key: Array<UInt8> = (key.data(using: .utf8)?.bytes)!
let iv: Array<UInt8> = (iv.data(using: .utf8)?.bytes)!
do {
let decrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(data)
let decryptedData = Data(decrypted)
guard let value = String.init(data: decryptedData, encoding: .utf8) else {
return "error"
}
return value
} catch {
print(error)
return "error"
}
}
Maybe it will help someone and save some time.

AES Encryption to strange characters

I am using AES Encryption in swift 3, I use this CryptoSwift library.
This is my code to encrypt a string and the result is readable string: /QOEtrf3o8buv2wA9FeAyg==.
How can I get the strange character (non readable) like this: Ί�^��h��y^ғ?
var input = "CryptoSwift"
var key = "passwordpassword"
var iv = "drowssapdrowssap"
func aesEncrypt(input: String, key: String, iv: String) throws -> String {
let data = input.utf8
let encrypted = try! AES(key: key, iv: iv, blockMode: .CBC, padding: PKCS7()).encrypt([UInt8](data))
let encryptedData = Data(encrypted)
return encryptedData.base64EncodedString()
}
let encrypted = try! aesEncrypt(input: input, key: key, iv: iv)
print("encrypted: \(encrypted)")
---------
Result: /QOEtrf3o8buv2wA9FeAyg==
I want the result something like this: Ί�^��h��y^ғ, the strange characters.
You shouldn't convert it to Base64.
let encrypted = try! AES(key: key, iv: iv, blockMode: .CBC, padding: PKCS7()).encrypt([UInt8](data))
let encryptedData = Data(bytes: UnsafePointer<UInt8>(encrypted), count: Int(encrypted.count))
// let encryptedString = String(data: encryptedData,encoding: String.Encoding.utf8)
// use the encryptedData to write it into a file.
"Ί�^��h��y^ғ" isn't a proper string. The character "�" means "this isn't a character." (It's technical name is the "substitution character" that is used when a byte sequence is not valid for the Unicode-based encoding you're using). Since "�" could be many different byte sequences, "Ί�^��h��y^ғ" isn't really meaningful. There are a huge number of byte sequences that would decode into that nonsense string.
You're getting a "readable string" because you're encoding the random bytes that come out of the encryption function in Base64.
It's not really clear what you mean by "wanting" something that includes � (since that's nonsense). If you want the data, just return the Data (don't call base64EncodedString()). As a general rule, this is what you want to work with. Encrypted data is Data, it's not `String.
What are you trying to do that you want a nonsense string that has lost information in the encoding?
You're returning a base64 encoded string which will always be readable ASCII. I'm unfamiliar with CryptoSwift, but if you can find some way to return the raw encrypted data, it should look the way you want.
Here is how I use it to properly decrypt and encrypt strings. You need to make string in hexString and hexString in data later. This is how CryptoSwift work.
extension String{
func aesEncrypt(key: String, iv: String) throws -> String {
let data = self.data(using: .utf8)!
let encrypted = try! AES(key: key, iv: iv, blockMode: .CBC).encrypt([UInt8](data))
let encryptedData = Data(encrypted)
try? encryptedData.toHexString().aesDecrypt(key: key, iv: iv)
return encryptedData.toHexString()
}
func aesDecrypt(key: String, iv: String) throws -> String {
let data = self.dataFromHexadecimalString()!
print(data)
let decrypted = try! AES(key: key, iv: iv, blockMode: .CBC).decrypt([UInt8](data))
let decryptedData = Data(decrypted)
return String(bytes: decryptedData.bytes, encoding: .utf8) ?? "Could not decrypt"
}
func dataFromHexadecimalString() -> Data? {
var data = Data(capacity: characters.count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
let byteString = (self as NSString).substring(with: match!.range)
var num = UInt8(byteString, radix: 16)
data.append(num!)
}
return data
}
}
extension Data {
public var bytes: Array<UInt8> {
return Array(self)
}
public func toHexString() -> String {
return self.bytes.toHexString()
}
}

iOS - Decrypt values encrypted by AES

I need decrypt value encrypted very similar to first example in PHP mcrypt-encrypt
This is what I know:
iv is base64 encoded
values are base64 encoded as well
After decoding both values from base64 then I should use decrypt method similar to PHP mcrypt-decrypt
I am using CryptoSwift library and I created this helper method (it needs to use parameters and not values in code, it's just until I get it working):
class func aesDecrypt(value: String, key: String) {
let vector = "8Z2IwsEwZ5lh27kFUmhiww=="
let vectorData = Data(base64Encoded: vector)
let vectorDecodedString = String(data: vectorData!, encoding: .unicode)
print("Vector decoded: \(vectorDecodedString)") // foo
let key = "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3"
let manufacture = "t0gEQWTxKgrGCOqXYOIuf6syF7nm1oCrwJVsxUJvw6e2sRQ25TgmML6vzfA3YFFe"
let keyBytes: [UInt8] = Array(key.utf8) //16
let ivBytes: [UInt8] = [UInt8](vectorData!)//Array(vectorDecodedString!.utf8)
let manufactureData = Data(base64Encoded: manufacture)
let valueInBytes = [UInt8](manufactureData!)
do {
let aes = try AES(key: keyBytes, iv: ivBytes, blockMode: .CBC)
let decryptedBytes = try aes.decrypt(valueInBytes)
let decryptedData = Data(bytes: decryptedBytes)
let decryptedString = String(bytes: decryptedBytes, encoding: .utf8)
let decryptedString2 = String(data: decryptedData, encoding: .utf8)
print("decryptedString: \(decryptedString)")
} catch let error {
print(error.localizedDescription)
// some error
}
}
Values in code I get from server. I tried AES with bytes or with strings but without luck. What's wrong with my code? How could I fix it? Thanks for help

CryptoSwift AES128-CBC with Swift

I'm getting this error while decrypting an AES128CBC encrypted JSON:
assertion failed: Block size and Initialization Vector must be the
same length!: file ##### for
iOS/CryptoSwift/Sources/CryptoSwift/AES.swift, line 97
I'm using the CryptoSwift Framework with the latest Xcode.
My Method:
func aes128(key: String, iv: String) throws -> String?{
if let aes: AES = try AES(key: key, iv: iv, blockMode: .CBC){
if let encrypted: [UInt8] = try aes.encrypt([UInt8](self.utf8), padding: PKCS7()){
return String(data: NSData.withBytes(encrypted), encoding: NSUTF8StringEncoding)
}
}
return nil
}
Call:
do{
print(try dataStr.aes128("8e0c0e73f97f2eb386ad75ba86051334", iv: "aa17ffc4ea4b1eac8fa0b56872f34e5f"))
}catch{
}
My Method:
func aes128(key: [UInt8], iv: [UInt8]) throws -> String?{
let data = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions(rawValue: 0))
let dec = try AES(key: key, iv: iv, blockMode:.CBC).decrypt(data!.arrayOfBytes(), padding: PKCS7())
let decData = NSData(bytes: dec, length: Int(dec.count))
let result = NSString(data: decData, encoding: NSUTF8StringEncoding)
return String(result!)
}
The call:
do{
let secret: [UInt8] = self.getAuthSecret(.LoginSecret)!.byte
let ivSlice = secret[0..<16]
let ivArray = Array<UInt8>(ivSlice)
let keySlice = secret[16..<32]
let keyArray = Array<UInt8>(keySlice)
print(try dataStr.aes128(keyArray, iv: ivArray))
}catch{
}

Swift CryptoSwift library causing error "fatal error: Array index out of range"

i have used CryptoSwift for AES encryption/decryption. when i run this code it throws error:
"fatal error: Array index out of range".
using reference from here
What can be the cause for this?
Any suggestion will be most appreciate.
code:
let key = "1234567890123456" // key
let iv = "1234567890123456" // random
let message = "This is test string"
override func viewDidLoad() {
super.viewDidLoad()
// encrypt
let encrypted = AES(key: key, iv: iv, blockMode: .CBC)
let enc = encrypted?.encrypt(message.utf8Array, padding: PKCS7())
println("enc >> \(enc)")
// decrypt
let decrypted = AES(key: key, iv: iv, blockMode: .CBC)
let dec = encrypted?.decrypt(enc!, padding: PKCS7())
println("dec >> \(dec)")
The problem may be here: message.utf8Array, where you convert String to Array. Here is working example:
let key = "1234567890123456" // key
let iv = "1234567890123456" // random
let message = "This is test string"
let aes = AES(key: key, iv: iv, blockMode: .CBC)
// encrypt
let enc = try! aes?.encrypt(message.dataUsingEncoding(NSUTF8StringEncoding)!.arrayOfBytes(), padding: PKCS7())
print("enc >> \(enc)")
// decrypt
let dec = try! aes?.decrypt(enc!, padding: PKCS7())
let str = NSString(data: NSData.withBytes(dec!), encoding: NSUTF8StringEncoding)
print("dec >> \(str)")

Resources