Encryption is not working in Swift4.2 using CommonCrypto. Throwing error 4301 - swift4

I have been trying to implement encryption using CommonCrypto library in swift 4.2. But no luck, ending up with some unknown error.
Somebody please look at this code and help me.
func encrypty(data value: String) -> EncryptionResult {
guard var messageData = value.data(using: .utf8), var key = getSecretkey()?.data(using: .utf8) else {
return EncryptionResult.failure
}
//iv ata
guard let ivData = generateRandomBytes(of: Int32(SecurityConstants.blockSize))?.data(using: .utf8) else {
return EncryptionResult.failure
}
//output
var outputData = Data(count: (messageData.count + SecurityConstants.blockSize + ivData.count))
var localOutput = outputData
//output length
var outputLength: size_t = 0
//encyrption
let status = key.withUnsafeBytes { keyBytes in
messageData.withUnsafeBytes { messageBytes in
localOutput.withUnsafeMutableBytes { mutableOutput in
ivData.withUnsafeBytes { ivDataBytes in
CCCrypt( CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES128),
CCOptions(kCCOptionPKCS7Padding),
keyBytes,
key.count,
ivDataBytes,
messageBytes,
messageData.count,
mutableOutput,
outputData.count,
&outputLength)
}
}
}
}
guard status == Int32(kCCSuccess) else {
logError("Error in encryption")
return EncryptionResult.failure
}
outputData.count = outputLength
return EncryptionResult.success(value: outputData.base64EncodedString())
}

Error -4310 is kCCKeySizeError (see CommonCryptoError.h). That means your key is not the right size.
Looking at this code, this in particular is very suspicious:
getSecretkey()?.data(using: .utf8)
If a key is decodable as UTF-8, it's not a proper key. You seem to have the same problem with your IV. I suspect that generateRandomBytes() does not quite do what it says it does. It's also not going to be possible to decrypt this data because you throw away the random IV (which the decryptor will require). You create room for it in the output (which is good), but you never write it.

Related

Create a Secure Random number in iOS using Swift?

public func createSecureRandomKey(numberOfBits: Int) -> Any {
let attributes: [String: Any] =
[kSecAttrKeyType as String:CFString.self,
kSecAttrKeySizeInBits as String:numberOfBits]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
return ""
}
return privateKey
}
I am trying to create Secure random number like above way, but returning nothing, Could any one please help me. Thanks.
It looks like you are using the wrong function. With your function you are generating a new key. But as your title says you want to generate secure random numbers.
For this there is a function called: SecRandomCopyBytes(::_:)
Here is a code snippet taken from the official apple documentation how to use it:
var bytes = [Int8](repeating: 0, count: 10)
let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
if status == errSecSuccess { // Always test the status.
print(bytes)
// Prints something different every time you run.
}
Source: Apple doc

Error validating CMS signature

For the past 2 weeks I've been banging my head against a wall trying to create and validate CMS signatures in Swift 4 using OpenSSL. My code is ultimately destined to be run on Linux, so I can't use the macOS Security framework. I believe I have finally gotten CMS signature creation working properly. My code for that looks like this:
let testBundle = Bundle(for: type(of: self))
guard let textUrl = testBundle.url(forResource: "test_message", withExtension: "txt"),
let signingKeyUrl = testBundle.url(forResource: "signing_key", withExtension: "pem"),
let signingCertUrl = testBundle.url(forResource: "signing_cert", withExtension: "pem") else {
exit(1)
}
let certFileObject = signingCertUrl.path.withCString { filePtr in
return fopen(filePtr, "rb")
}
defer {
fclose(certFileObject)
}
let keyFileObject = signingKeyUrl.path.withCString { filePtr in
return fopen(filePtr, "rb")
}
defer {
fclose(keyFileObject)
}
guard let key = PEM_read_PrivateKey(keyFileObject, nil, nil, nil),
let cert = PEM_read_X509(certFileObject, nil, nil, nil) else {
exit(1)
}
OpenSSL_add_all_ciphers()
OpenSSL_add_all_digests()
OPENSSL_add_all_algorithms_conf()
guard let textData = FileManager.default.contents(atPath: textUrl.path) else {
exit(1)
}
guard let textBIO = BIO_new(BIO_s_mem()) else {
print("Unable to create textBIO")
exit(1)
}
_ = textData.withUnsafeBytes({dataBytes in
BIO_write(textBIO, dataBytes, Int32(textData.count))
})
guard let cms = CMS_sign(cert, key, nil, textBIO, UInt32(CMS_BINARY)) else {
exit(1)
}
When I debug this code, I see that the cms object is being set after the CMS_sign call, so I believe that the signature was generated properly. Right after this, I'm trying to validate the signature I just created. That code looks like this:
let store = X509_STORE_new()
X509_STORE_add_cert(store, cert)
let outBIO = BIO_new(BIO_s_mem())
let result = CMS_verify(cms, nil, store, nil, outBIO, 0)
print("result : \(result)")
if result != 1 {
let errorCode: UInt = ERR_get_error()
print("ERROR : \(String(format: "%2X", errorCode))")
}
When I run this code, however, result == 0, indicating an error. The error code that OpenSSL is returning is 0x2E099064. I ran this command:
openssl errstr 0x2E099064
Which gave me this info about the error:
error:2E099064:CMS routines:func(153):reason(100)
After a bit more digging, I think that the error corresponds to PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH. I got that from the pkcs7.h file here. I'm not 100% that this is the correct error message, however.
My question is, why is my signature validation failing? I'm using the exact same certificate to validate the signature. All of this code is inline, so nothing is getting lost anywhere. Can any of you give me an idea where things are going wrong?

how to add triple des encryption decryption in swift

i am very tensed last 2 days due to encryption / decryption in triple Des in swift i am follow below link but not its show error where i get libraries of CCAlgorithem and CCOptions please check below image and please help me this
Note: I'm New In Swift Xcode
how to add these library in my code i'm new in swift
import UIKit
import CryptoSwift
class CypherSwift: NSObject {
func tripleDesEncrypt(pass: String) -> String{
//help from this thread
//http://stackoverflow.com/questions/25754147/issue-using-cccrypt-commoncrypt-in-swift
let keyString = "25d1d4cb0a08403e2acbcbe0"
let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let message = pass
let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let cryptData = NSMutableData(length: Int(data.length) + kCCBlockSize3DES)!
let keyLength = size_t(kCCKeySize3DES)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyData.bytes, keyLength,
nil,
data.bytes, data.length,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
// Not all data is a UTF-8 string so Base64 is used
var base64cryptString = cryptData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
print("base64cryptString = \(base64cryptString)")
base64cryptString = base64cryptString + "\n"
return encodeString(base64cryptString)
} else {
print("Error: \(cryptStatus)")
}
return ""
}
func encodeString(str: String) -> String{
let customAllowedSet = NSCharacterSet(charactersInString:"==\n").invertedSet
let escapedString = str.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
print("escapedString: \(escapedString)")
return escapedString!
}
}
image of error
tiple des link 1
triple des link 2
Unfortunately, there's currently no pre-defined Swift module for CommonCrypto, which means that you'll either have to create one yourself in a module.modulemap file, or import it in your bridging header. If you're making an app and not a framework, the latter is the easiest: just create a bridging header (if you don't have one, just add an Objective-C source file to the project and it'll offer to create one automatically; you can delete the Objective-C source file afterwards). Next, add this to the bridging header:
#import <CommonCrypto/CommonCrypto.h>
Note that if you're making a framework, the bridging header won't work and you'll have to make a modulemap instead (let me know if this is the case, and I'll edit something into the answer).
Anyway, the above will get rid of all the errors about kCC things not being found. Now that that's done, there are still a few things in the code that need fixing.
First of all, get rid of the unnecessary use of NS classes. Change:
let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
to:
let keyData = keyString.data(using: .utf8)!
The ! is acceptable in this case, since we know what keyString is and we know that it's definitely always convertible to UTF-8.
Now, do the same thing for data. Unfortunately in this case, message depends on user input, so we shouldn't use !—if the message turns out not to be convertible to UTF-8, ! will cause your app to crash, which usually isn't what you want. It's better to use guard let and then bail if the conversion fails, either by making your function's return value optional and returning nil or adding throws to your function's return value and throwing an error:
guard let data = message.data(using: .utf8) else {
return nil
OR:
throw CocoaError(.fileReadInapplicableStringEncoding) // or some custom error
}
The next issue is the use of bytes on your Data object. In Swift, this is not allowed, because it's unsafe; if the Data is deallocated before you're done with bytes, you'll crash or run into other weird behavior. Instead, you should use withUnsafeBytes, and do the work requiring the bytes inside a closure. This is safer, since the Data is guaranteed to be valid at least until the closure returns. Since we have three separate Datas that we need the bytes of, this is kind of unwieldy with a triple-nested closure, but we can do it:
let cryptStatus = keyData.withUnsafeBytes { (keyBytes: UnsafePointer<UInt8>) in
data.withUnsafeBytes { (dataBytes: UnsafePointer<UInt8>) in
cryptData.withUnsafeMutableBytes { (cryptBytes: UnsafeMutablePointer<UInt8>) in
CCCrypt(operation,
algoritm,
options,
keyBytes,
keyLength,
nil,
dataBytes,
data.count,
cryptBytes,
cryptData.count,
&numBytesEncrypted)
}
}
}
After that, you've just got some more Objective-C-isms to make properly Swifty, and your encrypt function should be done:
cryptData.count = Int(numBytesEncrypted)
// Not all data is a UTF-8 string so Base64 is used
var base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters)
The only problem I see in the encode function is a few Objective-C-isms that you should modernize:
let customAllowedSet = CharacterSet(charactersIn: "==\n").inverted
let escapedString = str.addingPercentEncoding(withAllowedCharacters: customAllowedSet)
There's also the calling convention of your encode function; func encodeString(str: String) means you'll have to call it like return encodeString(str: base64cryptString) with the label present. If you want to call it without the label, you can change the signature to func encodeString(_ str: String).

Convert Dictionary to Base64: error Segmentation fault 11

I am trying to create JSON Web Token using JSONSerialization class, Swift 3 and Xcode 8.1, but my project fails to build with error:
Command failed due to signal: Segmentation fault 11.
Anyone knows why my code is not correct?
If I comment out this code from the project, the project builds.
let customerError = "Custom Error"
enum headerError: Error {
case customerError
}
let headerJWT: [Dictionary] = ["alg":"RS256","typ":"JWT"]
//Convert headerJWT to Data
do {
let headerJWTData: Data = try? JSONSerialization.data(withJSONObject:headerJWT,options: JSONSerialization.WritingOptions.prettyPrinted)
} catch headerError.customerError {
print("could not make data")
}
//Convert headerData to string utf8
do {
let headerJWTString = try String(data: headerJWTData,encoding:String.Encoding.utf8) as! String
} catch {
print("string could not be created")
}
//Convert headerJWTString to base64EncodedString
do {
let headerJWTBase64 = try Data(headerJWTString.utf8).base64EncodedString()
} catch {
"base64 could not be created"
}
Once you create the Data from using JSONSerialization, you simply use the method from Data to get a base64 encoded string.
let headerJWT: [Dictionary] = ["alg":"RS256","typ":"JWT"]
do {
let headerJWTData: Data = try? JSONSerialization.data(withJSONObject:headerJWT,options: JSONSerialization.WritingOptions.prettyPrinted)
let headerJWTBase64 = headerJWTData.base64EncodedString()
} catch headerError.customerError {
print("could not make data")
}
You can pass different options to base64EncodedString() depending on what format you need the base64 string to be in.

How do I encode an unmanaged<SecKey> to base64 to send to another server?

I'm trying to use key pair encryption to validate identity between my app and my PHP server. To do this I need to send the public key over to the server after I generate it in my app.
if let pubKey = NSData(base64EncodedData: publicKey, options: NSDataBase64DecodingOptions.allZeros)! {
println(pubKey)
}
publicKey is of type Unmanaged<SecKey>.
The error I'm getting in the above code is: Extra argument 'base64EncodedData' in call
How would I do this? Is there a better way?
Edit: This is how the keypair is generated:
var publicKeyPtr, privateKeyPtr: Unmanaged<SecKey>?
let parameters = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): 2048
]
let result = SecKeyGeneratePair(parameters, &publicKeyPtr, &privateKeyPtr)
let publicKey = publicKeyPtr!.takeRetainedValue()
let privateKey = privateKeyPtr!.takeRetainedValue()
let blockSize = SecKeyGetBlockSize(publicKey)
Edit 2: So the issue is that SecKey is not NSData, so my question here should be: How do I convert a publicKey:SecKey to NSData?
It seems that you can temporary store the key to keychain and then get it back and convert it to data:
func convertSecKeyToBase64(inputKey: SecKey) ->String? {
// First Temp add to keychain
let tempTag = "de.a-bundle-id.temp"
let addParameters :[String:AnyObject] = [
String(kSecClass): kSecClassKey,
String(kSecAttrApplicationTag): tempTag,
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecValueRef): inputKey,
String(kSecReturnData):kCFBooleanTrue
]
var keyPtr: Unmanaged<AnyObject>?
let result = SecItemAdd(addParameters, &keyPtr)
switch result {
case noErr:
let data = keyPtr!.takeRetainedValue() as! NSData
// Remove from Keychain again:
SecItemDelete(addParameters)
let encodingParameter = NSDataBase64EncodingOptions(rawValue: 0)
return data.base64EncodedStringWithOptions(encodingParameter)
case errSecDuplicateItem:
println("Duplicate Item")
SecItemDelete(addParameters)
return nil
case errSecItemNotFound:
println("Not found!")
return nil
default:
println("Error: \(result)")
return nil
}
}
While the fact is barely documented, you can pull out everything you need (that is, modulus and exponent) from the SecKey using SecKeyCopyAttributes.
See here for the details.
Swift 4 method to get base64 string from SecKey, publicKey :)
guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey!, nil) else {
NSLog("\tError obtaining export of public key.")
return ""
}
let publicKeyNSData = NSData(data: publicKeyData as Data)
let publicKeyBase64Str = publicKeyNSData.base64EncodedString()