Md5 3Des Encryption Swift

MD5 3DES encryption Swift

So it turns out I was completely overcomplicating this.

There is a really useful article already
http://www.stackoverflow.dluat.com/questions/31004609/how-to-convert-common-crypto-code-from-objective-c-to-swift

I didn't need to import any external libraries or SDKs, all I needed was a bridging header and to #import <CommonCrypto/CommonCrypto.h>

override func viewDidLoad() {
super.viewDidLoad()
myEncrypt("my string to encrypt")
}

func myEncrypt(encryptData:String) -> NSData?{

var myKeyData : NSData = ("myEncryptionKey" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
var myRawData : NSData = encryptData.dataUsingEncoding(NSUTF8StringEncoding)!
var iv : [UInt8] = [56, 101, 63, 23, 96, 182, 209, 205] // I didn't use
var buffer_size : size_t = myRawData.length + kCCBlockSize3DES
var buffer = UnsafeMutablePointer<NSData>.alloc(buffer_size)
var num_bytes_encrypted : size_t = 0

let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)

var Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm, options, myKeyData.bytes, keyLength, nil, myRawData.bytes, myRawData.length, buffer, buffer_size, &num_bytes_encrypted)

if UInt32(Crypto_status) == UInt32(kCCSuccess){

var myResult: NSData = NSData(bytes: buffer, length: num_bytes_encrypted)

free(buffer)
println("my result \(myResult)") //This just prints the data

let keyData: NSData = myResult
let hexString = keyData.toHexString()
println("hex result \(hexString)") // I needed a hex string output


myDecrypt(myResult) // sent straight to the decryption function to test the data output is the same
return myResult
}else{
free(buffer)
return nil
}
}


func myDecrypt(decryptData : NSData) -> NSData?{

var mydata_len : Int = decryptData.length
var keyData : NSData = ("myEncryptionKey" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!

var buffer_size : size_t = mydata_len+kCCBlockSizeAES128
var buffer = UnsafeMutablePointer<NSData>.alloc(buffer_size)
var num_bytes_encrypted : size_t = 0

var iv : [UInt8] = [56, 101, 63, 23, 96, 182, 209, 205] // I didn't use

let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)

var decrypt_status : CCCryptorStatus = CCCrypt(operation, algoritm, options, keyData.bytes, keyLength, nil, decryptData.bytes, mydata_len, buffer, buffer_size, &num_bytes_encrypted)

if UInt32(decrypt_status) == UInt32(kCCSuccess){

var myResult : NSData = NSData(bytes: buffer, length: num_bytes_encrypted)
free(buffer)
println("decrypt \(myResult)")

var stringResult = NSString(data: myResult, encoding:NSUTF8StringEncoding)
println("my decrypt string \(stringResult!)")
return myResult
}else{
free(buffer)
return nil

}
}

I hope this helps someone.

iOS 3DES encryption with md5 key

md5 outputs a 128 bit (16 byte) hash, while 3DES takes a 168 bit (21 byte) key. I would suspect that passing an md5 hash into your encryption and/or decryption algorithm is causing some padding to take place along the way.

It would be better to either use SHA256 (which outputs a 256 bit hash) and truncate the output to 168 bits, or use AES-256 instead of 3DES with the full 256 bit hash as the key. Even better than that would be to use a proper key derivation function like PBKDF2 to create a key from a string password.

IOS 3DES in swift

You have to convert the arguments to the expected types. For example, kCCEncrypt is an Int, but the first parameter has the type CCOperation which is an alias for UInt32.
In contrast to (Objective-)C, Swift does not implicitly convert types:

var result = CCCrypt(
CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithm3DES),
CCOptions(kCCOptionPKCS7Padding | kCCOptionECBMode),
key,
UInt(kCCKeySize3DES),
...

MD5 of Data in Swift 3


    CC_MD5(data.bytes, CC_LONG(data.count), &digest)

As noted, bytes is unavailable because it's dangerous. It's a raw pointer into memory than can vanish. The recommended solution is to use withUnsafeBytes which promises that the target cannot vanish during the scope of the pointer. From memory, it would look something like this:

data.withUnsafeBytes { bytes in
CC_MD5(bytes, CC_LONG(data.count), &digest)
}

The point is that the bytes pointer can't escape into scopes where data is no longer valid.

For an example of this with CCHmac, which is pretty similar to MD5, see RNCryptor.

PBEWithMD5AndDES Encryption in iOS

Not sure what the protocol is here for accepting answers/upvoting them. I apologize if I'm doing this wrong. The answer turned out to be the lack of a final byte in the salt. I actually didn't need the IV with the 3DES encryption. I upvoted the other answer because it was helpful in understanding more about encryption.

Here's the final objective c class.

@implementation CryptoHelper

#pragma mark -
#pragma mark Init Methods
- (id)init
{
if(self = [super init])
{

}
return self;
}

#pragma mark -
#pragma mark String Specific Methods

/**
* Encrypts a string for social blast service.
*
* @param plainString The string to encrypt;
*
* @return NSString The encrypted string.
*/
- (NSString *)encryptString: (NSString *) plainString{

// Convert string to data and encrypt
NSData *data = [self encryptPBEWithMD5AndDESData:[plainString dataUsingEncoding:NSUTF8StringEncoding] password:@"1111"];



// Get encrypted string from data
return [data base64EncodingWithLineLength:1024];

}


/**
* Descrypts a string from social blast service.
*
* @param plainString The string to decrypt;
*
* @return NSString The decrypted string.
*/
- (NSString *)decryptString: (NSString *) encryptedString{

// decrypt the data
NSData * data = [self decryptPBEWithMD5AndDESData:[NSData dataWithBase64EncodedString:encryptedString] password:@"1111"];

// extract and return string
return [NSString stringWithUTF8String:[data bytes]];

}


#pragma mark -
#pragma mark Crypto Methods

- (NSData *)encryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password {
return [self encodePBEWithMD5AndDESData:inData password:password direction:1];
}

- (NSData *)decryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password {
return [self encodePBEWithMD5AndDESData:inData password:password direction:0];
}

- (NSData *)encodePBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password direction:(int)direction
{
NSLog(@"helper data = %@", inData);

static const char gSalt[] =
{
(unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA,
(unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA,
(unsigned char)0x00
};

unsigned char *salt = (unsigned char *)gSalt;
int saltLen = strlen(gSalt);
int iterations = 15;

EVP_CIPHER_CTX cipherCtx;


unsigned char *mResults; // allocated storage of results
int mResultsLen = 0;

const char *cPassword = [password UTF8String];

unsigned char *mData = (unsigned char *)[inData bytes];
int mDataLen = [inData length];


SSLeay_add_all_algorithms();
X509_ALGOR *algorithm = PKCS5_pbe_set(NID_pbeWithMD5AndDES_CBC,
iterations, salt, saltLen);



memset(&cipherCtx, 0, sizeof(cipherCtx));

if (algorithm != NULL)
{
EVP_CIPHER_CTX_init(&(cipherCtx));



if (EVP_PBE_CipherInit(algorithm->algorithm, cPassword, strlen(cPassword),
algorithm->parameter, &(cipherCtx), direction))
{

EVP_CIPHER_CTX_set_padding(&cipherCtx, 1);

int blockSize = EVP_CIPHER_CTX_block_size(&cipherCtx);
int allocLen = mDataLen + blockSize + 1; // plus 1 for null terminator on decrypt
mResults = (unsigned char *)OPENSSL_malloc(allocLen);


unsigned char *in_bytes = mData;
int inLen = mDataLen;
unsigned char *out_bytes = mResults;
int outLen = 0;



int outLenPart1 = 0;
if (EVP_CipherUpdate(&(cipherCtx), out_bytes, &outLenPart1, in_bytes, inLen))
{
out_bytes += outLenPart1;
int outLenPart2 = 0;
if (EVP_CipherFinal(&(cipherCtx), out_bytes, &outLenPart2))
{
outLen += outLenPart1 + outLenPart2;
mResults[outLen] = 0;
mResultsLen = outLen;
}
} else {
unsigned long err = ERR_get_error();

ERR_load_crypto_strings();
ERR_load_ERR_strings();
char errbuff[256];
errbuff[0] = 0;
ERR_error_string_n(err, errbuff, sizeof(errbuff));
NSLog(@"OpenSLL ERROR:\n\tlib:%s\n\tfunction:%s\n\treason:%s\n",
ERR_lib_error_string(err),
ERR_func_error_string(err),
ERR_reason_error_string(err));
ERR_free_strings();
}


NSData *encryptedData = [NSData dataWithBytes:mResults length:mResultsLen]; //(NSData *)encr_buf;


//NSLog(@"encryption result: %@\n", [encryptedData base64EncodingWithLineLength:1024]);

EVP_cleanup();

return encryptedData;
}
}
EVP_cleanup();
return nil;

}

@end

Encrypt and decrypt in SWIFT

Example question code updated.

Not sure what the output formatting code in the question was trying to accomplish.

Note that the 3DES uses a 24-byte key (kCCKeySize3DES is 24) and MD5 provides a 16-byte (CC_MD5_DIGEST_LENGTH is 16) result so there is a mis-match in key length.

func encrypt(dataString:String, keyString:String) -> NSData?
{
let keyData = md5(keyString)
let data : NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding)!
var numBytesEncrypted : size_t = 0
var encryptedData: NSMutableData! = NSMutableData(length: Int(data.length) + kCCBlockSize3DES)
let encryptedPointer = UnsafeMutablePointer<UInt8>(encryptedData.mutableBytes)
let encryptedLength = size_t(encryptedData.length)

let operation:CCOperation = UInt32(kCCEncrypt)
let algoritm:CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options:CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)

let status: CCCryptorStatus = CCCrypt(operation, algoritm, options,
keyData, keyLength,
nil,
data.bytes, data.length,
encryptedPointer, encryptedLength,
&numBytesEncrypted)
if Int32(status) == Int32(kCCSuccess) {
encryptedData.length = Int(numBytesEncrypted)
}
else {
encryptedData = nil
}

return encryptedData;
}

func md5(string: String) -> [UInt8] {
var digest = [UInt8](count: Int(CC_MD5_DIGEST_LENGTH), repeatedValue: 0)
if let data = string.dataUsingEncoding(NSUTF8StringEncoding) {
CC_MD5(data.bytes, CC_LONG(data.length), &digest)
}
return digest
}

Test:

let dataString = "Now is the time"
let keyString = "mykey"
let encryptedData = encrypt(dataString, keyString:keyString)
print("encryptedData: \(encryptedData!)")

let encryptedBase64 = encryptedData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
print("encryptedBase64: \(encryptedBase64)")

Output:

encryptedData: 8d88a2bc 00beb021 f37917c3 75b0ba1a

encryptedBase64: jYiivAC+sCHzeRfDdbC6Gg==

Note:

3DES, ECB mode and MD5 are not recommended and should not be used in new code, instead use AES, CBC mode with a random iv and PBKDF2 respetively.



Related Topics



Leave a reply



Submit