Different AES encryptors give me different results... why? - ios

I have tried using three different libraries to AES-encrypt a string.
When I use the tool found here I get the following results:
Input: "Test"
key: "MyEncryptionKey1MyEncryptionKey1" (256 Bit)
ECB mode.
this gives me the output Cidor8Ph7pZqPw0x2AwIKw==
But when i'm using the libraries in Swift I get different results.
Using RNCryptor
When i'm using RNcryptor i'm using the following code:
class func encryptMessage(message: String) throws -> String {
guard let messageData = message.data(using: .utf8) else { return message }
let cipherData = RNCryptor.encrypt(data: messageData, withPassword: key)
return cipherData.base64EncodedString()
}
output:
AwF8a+HziYkO4iHdcI3jY8p9QAY461DVgkjkYUFMkuh4A2a8FCfa4RgS9Z37QhJGxIL0Q20RE3BL4nmLQVFOfZmBpj8l0wj9YZgqZmrkxRFYQQ==
Using AESCrypt
When i'm using RNcryptor i'm using the following code:
class func encryptMessageAES(message: String) -> String{
guard let encryptedData = AESCrypt.encrypt(message, password: key) else { return message }
return encryptedData
}
Output:
T5/mR8UT/EXeUobPTLhcFA==
Also if i'm using CryptoSwift i'm getting a third result. My co-worker who does Android always gets the same result - matching the web tool.
I am totally new to encryption and I see that i'm doing something wrong. But I can't really realize what. I should also mention that this encryption is only used to not have chat messages in raw strings showing in Firebase, for those who have access to the database.

The definition of AES is quite precise and when things don't work between different implementations it's often due various things build on top of AES. The AES algorithm itself always operates on binary data. The data you encrypt needs to be binary. The key you use to encrypt with, needs to be binary and If an IV is in play, it also needs to be binary.
In all implementations where you provide data to the implementation that are not binary, a choice have been made on how that data is transformed into a format that can be used with AES. Sometimes these transformations are just simple data conversions like hex or base64 decoding, but other times whole new concepts are in play, like deriving encryption keys from passwords.
All of your three examples uses text as input for the Key, and each implementation have made some choice on how to support that.
The first page you link to has chosen to just interpret an ASCII string as a binary key. This is a terrible choice as it (in addition to being incompatible with everything else) effectively eliminates 1-2 bits per bytes of the key, reducing the strength considerable.
In the RNCryptor example you specify the key with withPassword: key. Here the RNCryptor team have chosen to use a PBKDF2 key deriving function to make an actual AES key. This solves a different usecase, where you have an potential weak password that needs stretching to be secure for encryption. If you have an actual key, this is not the way to go.
In the case of AESCrypt you also seems to be providing a password as input. It's not clear how that would be transformed to an actual key.

There is one more value which you’ll have to set in AES which is iv. So try to find that iv in all three libraries. And also try to set same value for iv. And then you may be able to get same results from all libraries.

Related

Katakana character ジ in URL being encoded incorrectly

I need to construct a URL with a string path received from my application server which contains the character: ジ
However, in Swift, the fileURLWithPath seems to encode it incorrectly.
let path = "ジ"
print(URL(fileURLWithPath: path))
print(URL(fileURLWithPath: path.precomposedStringWithCanonicalMapping))
Both print:
%E3%82%B7%E3%82%99
This expected URL path should be:
%E3%82%B8
What am I missing or doing wrong? Any help is appreciated.
There are two different characters, ジ and ジ. They may look the same, but they have different internal representations.
The former is “katakana letter zi”, comprised of a single Unicode scalar which percent-encodes as %E3%82%B8.
The latter is still a single Swift character, but is comprised of two Unicode scalars (the “katakana letter si” and “combining voiced sound mark”), and these two Unicode scalars percent-encode to %E3%82%B7%E3%82%99.
One can normalize characters in a string with precomposedStringWithCanonicalMapping, for example. That can convert a character with the two Unicode scalars into a character with a single Unicode scalar.
But your local file system (or, init(fileURLWithPath:), at least) decomposes diacritics. It is logical that the local file system ensures that diacritics are encoded in some consistent manner. (See Diacritics in file names on macOS behave strangely.) The fact that they are decomposed rather than precomposed is, for the sake of this discussion, a bit academic. When you send it to the server, you want it precomposed, regardless of what is happening in your local file system.
Now, you tell us that the “url path is rejected by the server”. That does not make sense. One would generally not provide a local file system URL to a remote server. One would generally extract a file name from a local file system URL and send that to the server. This might be done in a variety of ways:
You can use precomposedStringWithCanonicalMapping when adding a filename to a server URL, and it honors that mapping, unlike a file URL:
let path = "ジ" // actually `%E3%82%B7%E3%82%99` variant
let url = URL(string: "https://example.com")!
.appendingPathComponent(path.precomposedStringWithCanonicalMapping)
print(url) // https://example.com/%E3%82%B8
If sending it in the body of a request, use precomposedStringWithCanonicalMapping. E.g. if a filename in a multipart/form-data request:
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename.precomposedStringWithCanonicalMapping)\"\r\n")
body.append("Content-Type: \(mimeType)\r\n\r\n")
body.append(data)
body.append("\r\n")
Now, those are two random examples of how a filename might be provided to the server. Yours may vary. But the idea is that when you provide the filename, that you precompose the string in its canonical format, rather than relying upon what a file URL in your local file system uses.
But I would advise avoiding URL(fileURLWithPath:) for manipulating strings provided by the server. It is only to be used when actually referring to files within your local file system. If you just want to percent-encode strings, I would advise using the String method addingPercentEncoding(withAllowedCharacters: .urlPathAllowed). That will not override the precomposedStringWithCanonicalMapping output.
you could try this approach using dataRepresentation:
if let path = "ジ".data(using: .utf8),
let url = URL(dataRepresentation: path, relativeTo: nil) {
print("\n---> url: \(url) \n") //---> url: %E3%82%B8
}

iOS swift3 equivalent of "RSA/NONE/OAEPWithSHA256AndMGF1Padding"

I am getting decryption error on sever when I used SwiftyRSA to encrypt a text using publicKey on client.
I have referred this
RSA: encrypt in iOS, decrypt in Java but this is for SHA1.
I am using https://github.com/TakeScoop/SwiftyRSA library.
kSecPaddingOAEP and RSA/NONE/OAEPWithSHA1AndMGF1Padding works. But how Can I make it work for RSA/NONE/OAEPWithSHA256AndMGF1Padding
let str = "Clear Text"
let clear = try ClearMessage(string: str, using: .utf8)
let encrypted = try clear.encrypted(with: publicKey, padding: .OAEP)
I want to encrypt data in swift3 without touching server code.
As far as I know, Apple's security framework, it does not support OAEP padding with a SHA256 hash digest, but it can be done through the OpenSSL library.
https://github.com/x2on/OpenSSL-for-iPhone

Decrypting AES-256-CBC in Objective C

I am building an iPhone app which gets a decrypted string via JSON from a PHP backend.
In PHP I am encrypting the string like this:
$encrypt_method = "AES-256-CBC";
$secret_key = 'This is my secret key';
$secret_iv = 'This is my secret iv';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
}
In Objective C I tried to decrypt this string with BBEAS: https://github.com/benoitsan/BBAES
This is the code I have got in Objective C:
NSData* salt = [BBAES IVFromString:#"This is my secret iv"];
NSData *key = [BBAES keyBySaltingPassword:#"This is my secret key" salt:salt keySize:BBAESKeySize256 numberOfIterations:BBAESPBKDF2DefaultIterationsCount];
NSData *decryptedMessage = [BBAES decryptedDataFromString:#"RlVnd01XOE5teTNseDFGQ3JScVhkQT09" IV:salt key:key];
NSLog(#"Decrypted message: %#", decryptedMessage);
The log only shows a null object now.
I have found a duplicate post for C#: How to decrypt an AES-256-CBC encrypted string
EDIT:
Lets say that i can adjust the encoding in PHP. How should I encrypt the string in PHP to be decrypted in Objective C?
You are not doing the same thing in PHP as in iOS. I am not familiar with this BBAES framework, but what you seem to have is a password from which you are generating a 256 bit AES key using PBKDF key derivation, and using that to decrypt the data.
However, in PHP you are hashing your password and using it to encrypt your data, so you are probably using different AES keys for encryption and decryption. And I am not sure that IVs match either.
What you should do is:
In PHP, generate a random 16 byte IV for every encryption you do and use PBKDF key derivation to generate the 256 bit AES key from your password. Keep in mind that the salt and the number of iterations have to be the same in both PHP and iOS. After the encryption, append the IV to the encrypted data and send it.
In iOS, extract the IV from the received ciphertext (the last 16 bytes), generate the AES key from your password the same way you did before using the same salt and number of iterations, and decrypt the data (without the 16 byte IV at the end)
Edit:
As #Zaph pointed out, I forgot to mention that you should use also the same type of padding. BBAES seem to use PKCS7 padding.
To decrypt in Objective C you can use Apples's version of the CommonCrypto C library. It has a man page and there are already several posts that show decryption examples on Stack Overflow for example:
Determine if key is incorrect with CCCrypt kCCOptionPKCS7Padding-Objective C
which comes from the tutorial here:
http://robnapier.net/aes-commoncrypto
This also really helped me:
CCCrypt decrypting in AES CBC works even without IV
If you have trouble getting it working post some code.

SQLITE UTF-16 Encoding Issues

OK, I've been pulling my hair out for a couple of days on this issue. There are a couple of technologies at use here, first I'm using Unreal Engine 4 to develop an iOS game and I'm linking to a static lib of sqlite3, that I create the Database for on Windows.
On windows everything works fine, I create the database, and if you do Pragma encoding; it shows UTF-16LE.
However, when on IOS everything falls apart. First of all, if I even try to create a empty database in iOS using sqlite3_open16 function, it will create a database with a bunch of junk at the end of the name, and if I open it, and do pragma encoding it will say UTF-8 (empty database with no tables).
If I try to connect to my existing one, I will have success 'randomly' sometimes, I think this has to do again with the weird characters that are appearing at the end of my string which I suspect is encoding issues.
The function being used to open the database is this:
bool Open(const TCHAR* ConnectionString)
{
int32 Result = sqlite3_open16(ConnectionString, &DbHandle);
return Result == SQLITE_OK;
}
Which works fine in windows but has the issues above in ios.
According to their documentation they use USC-2. From what I can tell in the sqlite source, it will use UTF-16LE. Do I need to do something to convert between these two? Or is there something else I might be missing here? Does anyone have any ideas? I'm hoping someone who might not be familiar with UE4 might still have some guesses.
edit: a list of things I've tried:
Use the UTF-8 Functions SQLITE these appear to work fine. UE4 has a function TCHAR_TO_UTF8 and that worked.
Try to use Objective C to ensure the encoding of UTF-16LE, this gave me the 'random' success I describe above. Besides not only appearing to only randomly work with the weird random text at the end of the string sometimes - anytime I try to pull data out of the database now, it comes back as mostly random question marks '????' with the occasional chinese character. The function I used to do this with is:
const TCHAR* UChimeraSqlDatabase::UTF16_To_PlatformEncoding(FString UTF16EncodedString)
{
#if PLATFORM_IOS
const TCHAR* EncodedString = (const TCHAR *)([[[NSString stringWithFString : UTF16EncodedString] dataUsingEncoding:NSUTF16LittleEndianStringEncoding] bytes]);
#else
const TCHAR* EncodedString = *UTF16EncodedString;
#endif
return EncodedString;
}
Tried using Unreals .AppendChar to add L'\0' to the end of the String, without including number 2's method, no success.
If you're seeing weird characters at the end of the file name when calling sqlite3_16, it sounds like your UTF16 file name was not NULL terminated.
To specify the encoding of the database, you can actually create it with any of the sqlite3_open functions, but the key is that as soon as the database is created, you must immediately set the encoding:
PRAGMA encoding = "UTF-16le";
Once the encoding has been set, you can't change it, so make sure to do this first thing after creating the database.

How to get a unique hash or id from a URL in Cocoa?

In my application, I am reading RSS feeds and saving them to a Core Data db using the URL of each specific article as the key. Passing these URLs around the system can be problematic because they can be lengthy, and I'd like a way to generate a unique identifier to store in the db and just pass that around.
I'd also like it to be reconstructable using the same string so that if I get a duplicate URL, I can generate the identifier from it and simply check Core Data for the identifier.
Is there an easy way to do this?
When most people are talking about hashes, they are generally thinking about one-way hashes like SHA1, SHA2, or MD5. While these are imminently useful, they will not allow you to take a hash and reverse it into its original form. They will, however, allow you to do things like compare a user entered password with one they've entered before without ever having to store the actual password -- only the hash.
What you seem to want is string compression or deflation. Luckily, gzip is supported out of the box using the ASIHTTPRequest class. Here's some code for using gzip found in this discussion.
NSString *encodedGzippedString = #"GgAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyK+uE6X2SJPiyZ93eaX+TI9Lcuiatvx/wOwYc0HGgAAAA==";
NSData *decodedGzippedData = [NSData dataFromBase64String:encodedGzippedString];
NSData* unGzippedJsonData = [ASIHTTPRequest uncompressZippedData:decodedGzippedData];
NSString* unGzippedJsonString = [[NSString alloc] initWithData:unGzippedJsonData encoding:NSASCIIStringEncoding];
NSLog(#"Result: %#", unGzippedJsonString);
There is a very good article that discusses hashing using MD5 here:
http://cocoawithlove.com/2009/07/hashvalue-object-for-holding-md5-and.html
Using the CommonCrypto library, there are a number of hash algorithms already built in. You can use the MD5 hasing algorithm like this:
#import <CommonCrypto/CommonDigest.h>
char input[] = "Some data value.";
char result[16];
CC_MD5(input, strlen(input), result);
This will print out the hash in human-readable hex form:
printf("MD5 (\"%s\") = %02x%02x%02x%02x%02x%02x
%02x%02x%02x%02x%02x%02x
%02x%02x%02x%02x\n",
input,
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]);
If you would like more information on forward-only hashing, I posted some info as well as production-ready code in this SO answer.
Use SHA1 (apple implementation of it on iOS), it will meet all your requirements (re-running it with the same input generates the same output, changing a single character in the input drastically changes the output).
Using a security hashers like MD5 SHA1 or SHA256 leads to a source code which has to change a hasher function each time the algorithm will become obsolete or week. Then corporations which uses automated audit tools will reject the source code with those functions.
So if you need a hasher function for just removing special characters from urls it's better to have a custom hasher than one of those security hashers.

Resources