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()
}
}
Related
I am struggling with Swift 3. I am getting (hexString) response from server in encrypted form and I am first converting it into Data.
Below is my method to converting hexString to in Data:
extension String {
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, count: 1)
}
guard data.count > 0 else {
return nil
}
return data
}
}
After that I am Decrypting the data using CryptoSwift framework. Here below is my method to decrypt the data :-
func getAllShops(data : [String : AnyObject]) {
AFWrapper.sharedInstance.requestPOSTURL(My_URL, params: data, headers: nil, success: {(json) in
// Key for AES
let key = "My_Key"
// Iv for AES
let iv = "My_IV"
//Hex String from Server Response
let str = json["encrypted"].string!
do {
//Converting Hex String to Data
let dataStr = str.dataFromHexadecimalString()
//Decrypt the Data
let decryptedData = try AES(key: key, iv: iv, blockMode: .CBC, padding: NoPadding()).decrypt(dataStr!)
//Getting json string Response
var jsonResponse = String(bytes: decryptedData, encoding: .utf8)!
/*let response = JSON(jsonResponse)
print(response)
let validJson = JSONSerialization.isValidJSONObject(response)//(JSONSerialization.JSONObjectWithData(jsonData, options:nil, error: &error) != nil)
print("Valid JSON: \(validJson)")*/
/*let data = jsonResponse.data(using: String.Encoding.utf8)
let jsonsdd = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
print(jsonsdd)*/
}
catch {
print(error)
}
}, failure: {(Error) in
print(Error.localizedDescription)
})
}.
I am trying to convert that json String to in JSON object so that I can parse the data.
I tried with swiftyJSON and JSONSerialization in my code that part is commented. but not able to convert it.
I guess I am missing small thing that I don't know.
I’ve an issue with AES-128 encryption. The encrypted string in iOS is different as compared to Android.
Below is android code :
public class Encryption {
private static final String ALGORITHM = "AES";
private static final String UNICODE_FORMAT = "UTF8";
public static String encryptValue(String valueToEnc) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
String encryptedValue = new Base64().encode(encValue);
String urlEncodeddata = URLEncoder.encode(encryptedValue, "UTF-8");
return urlEncodeddata;
} catch (Exception e) {
}
return valueToEnc;
}
private static Key generateKey() throws Exception {
byte[] keyAsBytes;
keyAsBytes = "MySixteenCharKey".getBytes(UNICODE_FORMAT);
Key key = new SecretKeySpec(keyAsBytes, ALGORITHM);
return key;
}
}
Create string extension and use library CryptoSwift
// String+Addition.swift
import CryptoSwift
extension String {
func aesEncrypt(key: String) throws -> String {
var result = ""
do {
let key: [UInt8] = Array(key.utf8) as [UInt8]
let aes = try! AES(key: key, blockMode: ECB() , padding:.pkcs5) // AES128 .ECB pkcs7
let encrypted = try aes.encrypt(Array(self.utf8))
result = encrypted.toBase64()!
print("AES Encryption Result: \(result)")
} catch {
print("Error: \(error)")
}
return result
}
func aesDecrypt(key: String) throws -> String {
var result = ""
do {
let encrypted = self
let key: [UInt8] = Array(key.utf8) as [UInt8]
let aes = try! AES(key: key, blockMode: ECB(), padding: .pkcs5) // AES128 .ECB pkcs7
let decrypted = try aes.decrypt(Array(base64: encrypted))
result = String(data: Data(decrypted), encoding: .utf8) ?? ""
print("AES Decryption Result: \(result)")
} catch {
print("Error: \(error)")
}
return result
}
}
and to use
#IBAction func onBtnClicked(_ sender: Any) {
let value = "My value to be encrypted"
let key = "MySixteenCharKey"
print(key!)
let encryptedValue = try! value.aesEncrypt(key: key!)
print(encryptedValue)
}
For citation of this particular encryption code:
The 16 char length key implies AES-128
The code is without iVector, This implies ECB mode
Using padding as pkcs5 or pkcs7 did not made any difference in my case
Try this:
func encryptValue(stringToEncrypt:String) -> String{
var encryptedString: String = ""
let value = "MySixteenCharKey"
let input: Array<UInt8> = Array(stringToEncrypt.utf8)
let key: Array<UInt8> = Array("MySixteenCharKey".utf8)
do {
let encrypted = try AES(key: key, blockMode: .ECB, padding: PKCS7()).encrypt(input)
let base64 = encrypted.toBase64()
encryptedString = base64
} catch {
print(error)
}
return encryptedString
}
Create an extension of String and use this below function for encrypting and decrypting.
extension String {
//MARK: - Encrypt AES Method
/// This method will encrypt and return Cipher string
func aesEncrypt(key: String = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw", iv: String = "1234567890123456") -> String {
if let data = self.data(using: String.Encoding.utf8) {
do {
let enc = try AES(key: key, iv: iv, blockMode: .CBC, padding: PKCS7()).encrypt(data.bytes)
let encData = Data(bytes: enc, count: Int(enc.count))
let base64String: String = encData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0));
return base64String
}
catch let error {
print(error.localizedDescription)
return ""
}
}
return ""
}
//MARK: - Decrypt AES Method
/// This method will decrypt the Cipher string
func aesDecrypt(key: String = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw", iv: String = "1234567890123456") -> String {
if let data = Data(base64Encoded: self, options: Data.Base64DecodingOptions.init(rawValue: 0)) {
do {
let dec = try AES(key: key, iv: iv, blockMode: .CBC, padding: PKCS7()).decrypt(data.bytes)
let decData = Data(bytes: dec, count: Int(dec.count))
let result = String(data: decData, encoding: .utf8)
return result ?? ""
}
catch let error {
print(error.localizedDescription)
return ""
}
}
return ""
}
}
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
Here is my code :
func aesEncrypt(key: String, iv: String) throws -> String
{
let data = self.dataUsingEncoding(NSUTF8StringEncoding)
let enc = try AES(key: key, iv: iv, blockMode:.CBC).encrypt(data!.arrayOfBytes())
let encData = NSData(bytes: enc, length: Int(enc.count))
let base64String: String = encData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0));
let result = String(base64String)
return result
}
func aesDecrypt(key: String, iv: String) throws -> String
{
let data = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let dec = try AES(key: key, iv: iv, blockMode:.CBC).decrypt(data!.arrayOfBytes())
let decData = NSData(bytes: dec, length: Int(dec.count))
let result = NSString(data: decData, encoding: NSUTF8StringEncoding)
return String(result!)
}
The line:
data!.arrayOfBytes()
is producing the error
Ambiguous use of 'arrayOfBytes()'
. I have checked similar questions but none have helped.
The error perisist on both Xcode 7.3 Swift 2.2 and Xcode 8.0 Swift 2.3.
I commented out the PusherSwift framework in Xcdoe 7.3 and it worked.
I am not sure if it is a bug or something I have copied wrong.
If PusherSwift is pusher-websocket-swift, then it looks like they just dropped CryptoSwift directly into their module. If you're also importing CryptoSwift directly, then these will collide. This is a mistake by Pusher. They can't just drop another library into their own without taking special care that it will not collide.
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
}