I am trying to encrypt value using swift sodium with given public key.
However, the encrypted value is not the same as what's produced on server side.
I am not sure whether this piece of coding is right in swift.
The steps are similar to how its done in java.
Assume public key is in base64 string format.
Java:
String pubKey = "w6mjd11n9w9ncKfcuR888Ygi02ou+46ocIajlcUEmQ=";
String secret = "hithere"
byte[] pubKeyBytes = Base64.decode(pubKey,0);
SealedBox sealedDeal = new SealedBox(pubKeyBytes);
byte[] c = sealedDeal.encrypt(secret.getBytes());
String ciphertext = Base64.encodeToString(c, 0);
Swift:
let pubKey = "w6mjd11n9w9ncKfcuR888Ygi02ou+46ocIajlcUEmQ="
let dataDecoded:NSData = NSData(base64Encoded: pubKey, options: NSData.Base64DecodingOptions(rawValue: 0))!
let secret = "hithere".toData()!
let c : Data = sodium.box.seal(message: secret, recipientPublicKey: dataDecoded as Box.PublicKey)!
let ciphertext = c.base64EncodedString(options: .init(rawValue: 0))
Please tell me know what's wrong with the swift equivalent coding.
Thanks alot.
The encrypted value is supposed to be different, so that ciphertexts resulting from equivalent plaintexts are indistinguishable (see Ciphertext indistinguishability).
sodium.box.seal internally generates new nonce every time you are encrypting message, #Max is right, this is normal behave
You can use Detached mode to give same nonce, but this is a very bad idea
In your example you have used Anonymous Encryption I suggest you to take a look at Authenticated Encryption
Related
I have a project that retrieve data from API and shows in the app. But API uses AES encryption, I have aesKey and aesIV key and these keys are base64 encoded. I need to encode another string with these keys. To do that I use CryptoSwift library but when I try to use this keys to cipher the string, swift console warns me about invalidKeySize.I tried to decode from base64 to string but it did not work as well. These are the keys for an example;
Key and IV size are AES256, for encryption and decryption I need to use PKCS7 padding type with ECB/CBC block mode
aesKey = lHLBfVxlGoKoaCqWORJEHh3jOvC2EBx2VHGyNAdqYV0=
aesIV = 2spaSfljZ/cunRbuVkdphQ==
and CryptoSwift code block is:
let aes = try AES(key: "\(aesKeyString)", iv: "\(aesIVString)")
let cipherText = try aes.encrypt(Array("all".utf8))
The aesKey and aesIV from the snippet is Base64 encoded, so it's not really useful in that form. The convenience initializer you used is for a String, not base64 encoded data that you provided (that happened to be string, but it's different).
let aesKey = "lHLBfVxlGoKoaCqWORJEHh3jOvC2EBx2VHGyNAdqYV0="
let key = [UInt8](base64: aesKey)
let aesIV = "2spaSfljZ/cunRbuVkdphQ=="
let iv = [UInt8](base64: aesIV)
let aes = try AES(key: key, blockMode: CBC(iv: iv))
let cipherText = try aes.encrypt(Array("all".utf8))
I am attempting to interface with an existing device that uses AES-GCM with a 4-byte nonce (UInt32). This is a simple incremental counter that increases each time an operation occurs:
var cryptoCounter: UInt32 = 0
I then attempt to encrypt it and retrieve the values like so:
let key = SymmetricKey(data: sharedKey) // This is a 32-byte key.
let nonceData = withUnsafeBytes(of: cryptoCounter.bigEndian, Array.init) // Convert UInt32 to 4-byte data.
let nonce = try! AES.GCM.Nonce(data: Data(nonceData)) // This throws an invalid parameter size exception.
let encrypted = try! AES.GCM.seal(serialized, using: key, nonce: nonce)
However, the AES.GCM.Nonce doesn't work with fewer than 12 bytes, so the 4-byte nonce causes it to throw an error. I've tried padding the nonce with a spare 0'ed 8-bytes:
let nonceData = [0, 0, 0, 0, 0, 0, 0, 0] + withUnsafeBytes(of: cryptoCounter.bigEndian, Array.init)
But the encrypted value is rejected by the device, so I assume this isn't correct. If anyone has any suggestions on the best way to implement this Swift, that would be amazing! Thank you.
I figured out a solution that worked for me.
I used the excellent CryptoSwift library (7.8k stars on GitHub at time of writing):
let gcm = GCM(iv: withUnsafeBytes(of: cryptoCounter.bigEndian, Array.init), mode: .detached)
let aes = try! AES(key: [UInt8](sharedKey), blockMode: gcm, padding: .noPadding)
let encrypted = try! aes.encrypt([UInt8](serialized))
I'm starting to learn de-/encrypting with the CryptoKit.
Everything works fine, but I can not share my generated SymmetricKey.
Example:
let key = SymmetricKey(size: .bits256)
Well, I generate a symmetric key. Now I want to share the key, but how I can do that?
Inside the debugger the variable key is empty?
I check the encryption and decryption - works well - output shows the encrypted and decrypted data. How can I save my variable key for distribution?
I found a solution:
let savedKey = key.withUnsafeBytes {Data(Array($0)).base64EncodedString()}
This works great, but how can I save the variable savedKey (String) back into the variable key (SymmetricKey)?
You can do that by converting key string to Data and retrieve the key from it
let key = SymmetricKey(size: .bits256)
let savedKey = key.withUnsafeBytes {Data(Array($0)).base64EncodedString()}
if let keyData = Data(base64Encoded: savedKey) {
let retrievedKey = SymmetricKey(data: keyData)
}
Hope this helps :)
Trying to create a signature by using RFC 2104-compliant HMAC with the SHA256 hash algorithm. I am half-way done but stuck in converting a string to binary and then to base64 format.
Here is the instruction I am following.
Here is the code I made
let stringToSign = "GET\nwebservices.amazon.com\n/onca/xml\nAWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&AssociateTag=mytag-20&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers%2CReviews&Service=AWSECommerceService&Timestamp=2014-08-18T12%3A00%3A00Z&Version=2013-08-01"
let beforeCoversion = stringToSign.hmac(algorithm: .SHA256, key: "1234567890")
let binary = beforeCoversion.data(using: .utf8, allowLossyConversion: false)
let afterCoversion = binary?.base64EncodedString(options: [.lineLength64Characters])
print(beforeCoversion)
print(afterCoversion!)
Print
8fb6d93342d767d797799aee4ea5a6d8322f0d8554537c313cfa69fa25f1cd07
OGZiNmQ5MzM0MmQ3NjdkNzk3Nzk5YWVlNGVhNWE2ZDgzMjJmMGQ4NTU0NTM3YzMx
M2NmYTY5ZmEyNWYxY2QwNw==
I can see that I get 8fb6d93342d767d797799aee4ea5a6d8322f0d8554537c313cfa69fa25f1cd07 so my conversion is failed in converting a string to binary and then to base64 format. I believe beforeCoversion.data(using: .utf8, allowLossyConversion: false) can be used for converting a string to binary and binary?.base64EncodedString(options: [.lineLength64Characters]) can be used for converting to base64 format. Is that correct? sAny suggestions?
Easy way to solve this if you use amazon-api
pod 'AWSAPIGateway'
Then
let dataToSign = stringToSign.data(using: String.Encoding.utf8)
let conversion = AWSSignatureSignerUtility.hmacSign(dataToSign, withKey: "1234567890", usingAlgorithm: UInt32(kCCHmacAlgSHA256))!
Thanks Roozbeh Zabihollahi for the answer in Amazon Product Advertising API Signature in iOS
I'm trying to make OAuth module for Swift 2 in my application. I'm stucked with HMAC-SHA1 signature generating because my function returns incorrect base64 hmac-sha1 for signature. Can you help me with it? What's wrong?
func URLEncodedKey() -> String? {
let key = "efgh"
let string = "GET&http%3A%2F%2Fhost.net%2Fresource&name%3Dvalue%26name%3Dvalue%26oauth_consumer_key%3Dabcd%26oauth_nonce%3DxUwWEy3LVsI%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1441375089%26oauth_token%3Dijkl%26oauth_version%3D1.0"
guard let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
stringData = string.dataUsingEncoding(NSUTF8StringEncoding),
outputData = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH)) else {
return nil
}
outputData.length = Int(CC_SHA1_DIGEST_LENGTH)
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1),
keyData.bytes, keyData.length,
stringData.bytes, stringData.length,
outputData.mutableBytes)
return outputData
.base64EncodedStringWithOptions([])
}
For checking:
String for encode: in code
Correct: O8UjUTYX1UxKF93KaY/mta9HETs=
My (incorrect): f5elSONqP6nPdpgBIyroJTCN19s=
Correct encoder is here (javascript): https://oauth.googlecode.com/svn/code/javascript/example/signature.html
Your method must returns correct result as is.
See http://oauth.net/core/1.0/#signing_process:
The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] where the Signature Base String is the text and the key is the concatenated values (each first encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty.
The key should be "efgh&mnop" in this case.