I have a java code, where i used cryptography( Encryption and decryption). I want to use the same process on swift code.
//my java code for encryption in crypto class
class Crypto {
private SecretKeySpec skc;
private final static char[] hexArray = "0123456789abcdef".toCharArray();
String TAG = "TAG";
#RequiresApi(api = Build.VERSION_CODES.O)
Crypto(String token) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(("YourStrongKey" + token).getBytes("UTF-8"));
skc = new SecretKeySpec(thedigest, "AES/ECB/PKCS5Padding");
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
private byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
public byte[] encrypt(String clear) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skc);
byte[] input = clear.getBytes("utf-8");
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
cipher.doFinal(cipherText, ctLength);
Log.d(TAG, "encrypt: ciper: "+cipher.toString());
return cipherText;
}
public byte[] decrypt(byte[] buf, int offset, int len) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skc);
byte[] dec = new byte[cipher.getOutputSize(len - offset)];
int ctLength = cipher.update(buf, offset, len - offset, dec, 0);
cipher.doFinal(dec, ctLength);
Log.d(TAG, "encrypt: dec: "+dec.toString());
return dec;
}
}
//uses of java form main activity class
Crypto crypto;
String token = "Jpc3MiOiJodHRwczovL3NlY3VyZXRva2";
crypto = new Crypto(token);
JSONObject msg = new JSONObject();
msg.put("phoneData", "data1");
msg.put("countryData", "data2");
Log.d(TAG, "startHttpApiRequest: msg: "+msg);
String ss = msg.toString();
byte[] msgD = crypto.encrypt(ss);
//my swift code on playground
class SecretSpec {
var algorithm: String = "AES/ECB/PKCS7padding"
var key = [UInt8]()
func secretSpec(key: [UInt8], algorithm: String){
self.key = key
self.algorithm = algorithm
}
func getAlgorithm() -> String {
return self.algorithm
}
func getFormat() -> String {
return "RAW"
}
func getEncoded() -> [UInt8] {
return self.key
}
func hashCode() -> Int {
var retval: Int = 0
for i in 1...key.count-1 {
retval = retval + Int(key[i]) * Int(i)
}
if (algorithm.lowercased() == "tripledes"){
retval = retval ^ Int("desede".hashValue)
return retval
}else{
retval = retval ^ Int(algorithm.lowercased().hashValue)
return retval
}
}
}
extension String {
func aesEncrypt(key: String) -> String? {
if let keyData = key.data(using: String.Encoding.utf8),
let data = self.data(using: String.Encoding.utf8),
let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation, algoritm, options,
(keyData as NSData).bytes,keyLength,nil, (data as NSData).bytes, data.count,cryptData.mutableBytes, cryptData.length,&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
var bytes = [UInt8](repeating: 0, count: cryptData.length)
cryptData.getBytes(&bytes, length: cryptData.length)
var hexString = ""
for byte in bytes {
hexString += String(format:"%02x", UInt8(byte))
}
return hexString
}
else {
return nil
}
}
return nil
}
}
func MD5(_ string: String) -> String? {
let length = Int(CC_MD5_DIGEST_LENGTH)
var digest = [UInt8](repeating: 0, count: length)
if let d = string.data(using: String.Encoding.utf8) {
_ = d.withUnsafeBytes { (body: UnsafePointer<UInt8>) in
CC_MD5(body, CC_LONG(d.count), &digest)
}
}
return (0..<length).reduce("") {
$0 + String(format: "%02x", digest[$1])
}
}
var token = "YourStrongKeyJpc3MiOiJodHRwczovL3NlY3VyZXRva2"
var algorithm: String = "AES/ECB/PKCS5padding"
var tokenRes = MD5(token)
let digest = hexstringToBytes(tokenRes!)
var skcSpec = SecretSpec()
skcSpec.secretSpec(key: digest!, algorithm: algorithm)
print("hello: \(skcSpec)")
let msg: NSMutableDictionary = NSMutableDictionary()
msg.setValue("data1", forKey: "phoneData")
msg.setValue("data2", forKey: "countryData")
let msgData: NSData
var msgStr: String = ""
var requestUrl: String = ""
do {
msgData = try JSONSerialization.data(withJSONObject: msg, options: JSONSerialization.WritingOptions()) as NSData
msgStr = NSString(data: msgData as Data, encoding: String.Encoding.utf8.rawValue)! as String
} catch _ {
print ("JSON Failure")
}
var str = skcSpec.getEncoded()
print(str)
let skc = NSString(bytes: str, length: str.count, encoding: String.Encoding.ascii.rawValue)! as String
let eneMsg = msgStr.aesEncrypt(key: skc)!
print("encoded: \(eneMsg)")
it does not gives me the same output. please help me to finding same output. nb: java code is fixed for encryption and decryption.
Outputs:
in java:
ffe957f00bdd93cfe1ef1133993cc9d2d8682310c648633660b448d92098e7fa07ae25f600467894ac94ccdcbe4039b8
in swift:
2e130be30aa3d8ff7fdc31dc8ffe1c39afe987ccbf8481caed9c78b49624a31c68df63a899df130128af6852c82d9aea
I have tried to convert your Crypto class directly into Swift, and got this:
import Foundation
import CommonCrypto
func MD5(_ data: Data) -> Data {
let length = Int(CC_MD5_DIGEST_LENGTH)
var digest = Data(count: length)
data.withUnsafeBytes {bytes in
_ = digest.withUnsafeMutableBytes {mutableBytes in
CC_MD5(bytes.baseAddress, CC_LONG(bytes.count), mutableBytes.bindMemory(to: UInt8.self).baseAddress)
}
}
return digest
}
func hexStringToData(_ s: String) -> Data {
let len = s.count
var data = Data(count: len/2)
var start = s.startIndex
for i in 0..<len/2 {
let end = s.index(start, offsetBy: 2)
data[i] = UInt8(s[start..<end], radix: 16)!
start = end
}
return data
}
class Crypto {
private var key: Data
init(_ token: String) {
let theDigest = MD5(("YourStrongKey" + token).data(using: .utf8)!)
key = theDigest
}
public func encrypt(_ clear: String) -> Data? {
let input = clear.data(using: .utf8)!
var cipherText = Data(count: input.count + kCCBlockSizeAES128)
let keyLength = size_t(kCCKeySizeAES128)
assert(key.count >= keyLength)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var ctLength: size_t = 0
let cryptStatus = key.withUnsafeBytes {keyBytes in
input.withUnsafeBytes {inputBytes in
cipherText.withUnsafeMutableBytes {mutableBytes in
CCCrypt(operation, algoritm, options,
keyBytes.baseAddress, keyLength, nil,
inputBytes.baseAddress, inputBytes.count,
mutableBytes.baseAddress, mutableBytes.count,
&ctLength)
}
}
}
if cryptStatus == CCCryptorStatus(kCCSuccess) {
cipherText.count = Int(ctLength)
return cipherText
} else {
return nil
}
}
public func decrypt(_ buf: Data, _ offset: Int, _ len: Int) -> Data? {
var dec = Data(count: len)
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var ctLength :size_t = 0
let cryptStatus = key.withUnsafeBytes {keyBytes in
buf.withUnsafeBytes {inputBytes in
dec.withUnsafeMutableBytes {mutableBytes in
CCCrypt(operation, algoritm, options,
keyBytes.baseAddress, keyLength, nil,
inputBytes.baseAddress, inputBytes.count,
mutableBytes.baseAddress, mutableBytes.count,
&ctLength)
}
}
}
if cryptStatus == CCCryptorStatus(kCCSuccess) {
dec.count = Int(ctLength)
return dec
} else {
return nil
}
}
}
let token = "Jpc3MiOiJodHRwczovL3NlY3VyZXRva2"
let crypto = Crypto(token)
let msg = [
"phoneData": "data1",
"countryData": "data2",
]
let msgData = try! JSONSerialization.data(withJSONObject: msg)
let ss = String(data: msgData, encoding: .utf8)!
print(ss) //->{"phoneData":"data1","countryData":"data2"}
//### Be careful, this may be different than the result of JSONObject#toString() in Java.
//### Sometimes, outputs->{"countryData":"data2","phoneData":"data1"}
let msgD = crypto.encrypt(ss)!
print(msgD as NSData) //-><ffe957f0 0bdd93cf e1ef1133 993cc9d2 24e8b9a1 162520e5 54a3d8af 8f478db7 07ae25f6 00467894 ac94ccdc be4039b8>
//### When `ss` is {"phoneData":"data1","countryData":"data2"}
let decrypted = crypto.decrypt(msgD, 0, msgD.count)!
print(String(data: decrypted, encoding: .utf8)!) //->{"phoneData":"data1","countryData":"data2"}
In your Java code, your key String ("YourStrongKey" + token) gets two conversions until used as a binary key data for AES:
key: "YourStrongKey" + token
↓
UTF-8 bytes
↓
MD5 digest
But, in your Swift code, you are converting the key more times:
token: "YourStrongKeyJpc3MiOiJodHRwczovL3NlY3VyZXRva2"
↓
UTF-8 bytes (`d` in `MD5(_:)`)
↓
MD5 digest
↓
binary to HEX String conversion (return value from `MD5(_:)`)
↓
UTF-8 bytes (`keyData` in `aesEncrypt(key:)`)
There's no binary to HEX String conversion in your Java code and you should have not done that.
By the way, ECB is not considered to be a safe way to encrypt, you should better update your Java code.
Related
I have an android class which is encoding and decoding my text using a key but I want to create the same class for swift.
“I'm setting up a new server, and want to support UTF-8 fully in my web application. Where do I need to set the encoding/charsets?”
public class EncryptionDecryption {
String strResult;
public String Encrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
Log.v("GET Result from final:", results.toString());
strResult = Base64.encodeToString(results, 1);
Log.v("Encrypt01:", strResult);
Log.v("Encrypt02:", results.toString());
return strResult;
}
public String Decrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //this parameters should not be changed
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] results = new byte[text.length()];
//BASE64Decoder decoder = new BASE64Decoder();
try {
results = cipher.doFinal(Base64.decode(text, Base64.DEFAULT));
} catch (Exception e) {
Log.i("Error in Decryption", e.toString());
}
Log.i("Data", new String(results, "UTF-8"));
//return new String(results, "UTF-8"); // it returns the result as a String
return new String(results, "UTF-8");
}
For swift 4 I found this answer thanks all
import CommonCrypto
extension String {
func aesEncrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
if let keyData = key.data(using: String.Encoding.utf8),
let data = self.data(using: String.Encoding.utf8),
let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(keyData as NSData).bytes, keyLength,
iv,
(data as NSData).bytes, data.count,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters)
return base64cryptString
}
else {
return nil
}
}
return nil
}
func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
if let keyData = key.data(using: String.Encoding.utf8),
let data = NSData(base64Encoded: self, options: .ignoreUnknownCharacters),
let cryptData = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(keyData as NSData).bytes, keyLength,
iv,
data.bytes, data.length,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let unencryptedMessage = String(data: cryptData as Data, encoding:String.Encoding.utf8)
return unencryptedMessage
}
else {
return nil
}
}
return nil
}
}
Starting from Xcode 10.1 and Swift 4.2 you can use CommonCrypto pretty easy without to take care about Objective-C to Swift bridging.
just:
import CommonCrypto
read more about framework methods here https://developer.apple.com/security/
I have an example for a 3DES encryption that I have to follow in order to authenticate on NFC cards. Here is the example:
So 51E764602678DF2B becomes 577293FD2F34CA51 with key = 49454D4B41455242214E4143554F5946 and IV = 0000000000000000
I succeed to have the right result on this site:
http://tripledes.online-domain-tools.com/
I tried on swift with https://github.com/sgl0v/SCrypto as follow:
func testScrypto() {
let plaintext = "51E764602678DF2B".data(using: String.Encoding.utf8)!
let sharedSecretKey = "49454D4B41455242214E4143".data(using: String.Encoding.utf8)!
let IV = "0000000000000000".data(using: String.Encoding.utf8)!
let ciphertext = try! plaintext.encrypt(.tripleDES, options: .PKCS7Padding, key: sharedSecretKey, iv: IV)
let plaintext2 = try! ciphertext.decrypt(.tripleDES, options: .PKCS7Padding, key: sharedSecretKey, iv: IV)
print("cipher = \(ciphertext.hexString())")
print("plaintext2 = \(plaintext2.hexString())")
}
public extension Data {
func bytesArray<T: ExpressibleByIntegerLiteral>() -> [T] {
var bytes = Array<T>(repeating: 0, count: self.count)
(self as NSData).getBytes(&bytes, length:self.count * MemoryLayout<T>.size)
return bytes
}
func hexString() -> String {
let hexString = NSMutableString()
let bytes: [UInt8] = self.bytesArray()
for byte in bytes {
hexString.appendFormat("%02x", UInt(byte))
}
return hexString as String
}
}
and the result is:
cipher = d4c4a9637bcb4a435982330a42d1357b9e4539886a983535
plaintext2 = 35314537363436303236373844463242
35314537363436303236373844463242 is 51E764602678DF2B if i convert from hexstring to plaintext but the other string is not 577293FD2F34CA51 at all
I also tried this lib https://www.example-code.com/swift/crypt2_3des.asp
but the result is still wrong
I don't know if anybody has an idea how to do this on swift or is an expert in encryption ?
thanks !
I succeed to fix the issue
The issue was that the key was only 16 bytes and need to be 24, so I guess it was randomly filled but it was expected to be the first 8 bytes to be put back at the end of the 16 in order to do 24 ?
like this it works:
func fillKey(keyLength: size_t, key: Data) -> Data {
let missingBytes = keyLength - key.count
if missingBytes > 0 {
let keyBytes = (key as NSData).bytes
var bytes = [UInt8](repeating: UInt8(0), count: keyLength)
memccpy(&bytes[0], keyBytes.advanced(by: 0), Int32(key.count), key.count)
memccpy(&bytes[key.count], keyBytes.advanced(by: 0), Int32(missingBytes), missingBytes)
return Data(bytes: bytes)
} else {
return key
}
}
func my3DESEncrypt(encryptData: String, key: String, iv: String) -> Data? {
var myKeyData : Data = key.hexadecimal()!
let myIvData : Data = iv.hexadecimal()!
var myRawData : Data = encryptData.hexadecimal()!
let buffer_size : size_t = myRawData.count + kCCBlockSize3DES
var buffer = [UInt8](repeating: UInt8(0), count: buffer_size)
var num_bytes_encrypted : size_t = 0
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = 0
let keyLength = size_t(kCCKeySize3DES)
myKeyData = self.fillKey(keyLength: keyLength, key: myKeyData)
let Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm, options, (myKeyData as NSData).bytes, keyLength, (myIvData as NSData).bytes, (myRawData as NSData).bytes, myRawData.count, &buffer, buffer_size, &num_bytes_encrypted)
if UInt32(Crypto_status) == UInt32(kCCSuccess) {
let data = Data(bytes: buffer, count: num_bytes_encrypted)
return data
} else{
return nil
}
}
func my3DESDecrypt(decryptData : Data, key: String, iv: String) -> Data? {
let mydata_len : Int = decryptData.count
var myKeyData : Data = key.hexadecimal()!
let myIvData : Data = iv.hexadecimal()!
let buffer_size : size_t = mydata_len+kCCBlockSize3DES
var buffer = [UInt8](repeating: UInt8(0), count: buffer_size)
var num_bytes_encrypted : size_t = 0
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)
myKeyData = self.fillKey(keyLength: keyLength, key: myKeyData)
let decrypt_status : CCCryptorStatus = CCCrypt(operation, algoritm, options, (myKeyData as NSData).bytes, keyLength, (myIvData as NSData).bytes, (decryptData as NSData).bytes, mydata_len, &buffer, buffer_size, &num_bytes_encrypted)
if UInt32(decrypt_status) == UInt32(kCCSuccess){
let data = Data(bytes: buffer, count: num_bytes_encrypted)
return data
} else{
return nil
}
}
The plaintext data and key that have been provided are encoded in hexadecimals. You are however encoding them as UTF-8 text, which is not the same thing.
I have this Rsa swift code and it's work good and encrypt or decrepit data but when string.count is more than 132 char error decrepit and encrypt data , how can I decrepit and encrypt data for more than 132 char
my Rsa class is, I don't want separate my data
class RSAWrapper {
private var publicKey : SecKey?
private var privateKey : SecKey?
func generateKeyPair(keySize: UInt, privateTag: String, publicTag: String) -> Bool {
self.publicKey = nil
self.privateKey = nil
if (keySize != 512 && keySize != 1024 && keySize != 2048) {
// Failed
print("kelid kharab ast")
return false
}
let publicKeyParameters: [NSString: AnyObject] = [
kSecAttrIsPermanent: true as AnyObject,
kSecAttrApplicationTag: publicTag as AnyObject
]
let privateKeyParameters: [NSString: AnyObject] = [
kSecAttrIsPermanent: true as AnyObject,
kSecAttrApplicationTag: publicTag as AnyObject
]
let parameters: [String: AnyObject] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: keySize as AnyObject,
kSecPrivateKeyAttrs as String: privateKeyParameters as AnyObject,
kSecPublicKeyAttrs as String: publicKeyParameters as AnyObject
];
let status : OSStatus = SecKeyGeneratePair(parameters as CFDictionary, &(self.publicKey), &(self.privateKey))
return (status == errSecSuccess && self.publicKey != nil && self.privateKey != nil)
}
func encrypt(text: String) -> [UInt8] {
let plainBuffer = [UInt8](text.utf8)
var cipherBufferSize : Int = Int(SecKeyGetBlockSize((self.publicKey)!))
var cipherBuffer = [UInt8](repeating:0, count:Int(cipherBufferSize))
// Encrypto should less than key length
let status = SecKeyEncrypt((self.publicKey)!, SecPadding.PKCS1, plainBuffer, plainBuffer.count, &cipherBuffer, &cipherBufferSize)
if (status != errSecSuccess) {
print("Failed Encryption")
}
return cipherBuffer
}
func decprypt(encrpted: [UInt8]) -> String? {
var plaintextBufferSize = Int(SecKeyGetBlockSize((self.privateKey)!))
var plaintextBuffer = [UInt8](repeating:0, count:Int(plaintextBufferSize))
let status = SecKeyDecrypt((self.privateKey)!, SecPadding.PKCS1, encrpted, plaintextBufferSize, &plaintextBuffer, &plaintextBufferSize)
if (status != errSecSuccess) {
print("Failed Decrypt")
return nil
}
return NSString(bytes: &plaintextBuffer, length: plaintextBufferSize, encoding: String.Encoding.utf8.rawValue)! as String
}
func encryptBase64(text: String) -> String {
let plainBuffer = [UInt8](text.utf8)
var cipherBufferSize : Int = Int(SecKeyGetBlockSize((self.publicKey)!))
var cipherBuffer = [UInt8](repeating:0, count:Int(cipherBufferSize))
// Encrypto should less than key length
let status = SecKeyEncrypt((self.publicKey)!, SecPadding.PKCS1, plainBuffer, plainBuffer.count, &cipherBuffer, &cipherBufferSize)
if (status != errSecSuccess) {
print("Failed Encryption")
}
let mudata = NSData(bytes: &cipherBuffer, length: cipherBufferSize)
return mudata.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength64Characters)
}
func decpryptBase64(encrpted: String) -> String? {
let data : NSData = NSData(base64Encoded: encrpted, options: .ignoreUnknownCharacters)!
let count = data.length / MemoryLayout<UInt8>.size
var array = [UInt8](repeating: 0, count: count)
data.getBytes(&array, length:count * MemoryLayout<UInt8>.size)
var plaintextBufferSize = Int(SecKeyGetBlockSize((self.privateKey)!))
var plaintextBuffer = [UInt8](repeating:0, count:Int(plaintextBufferSize))
let status = SecKeyDecrypt((self.privateKey)!, SecPadding.PKCS1, array, plaintextBufferSize, &plaintextBuffer, &plaintextBufferSize)
if (status != errSecSuccess) {
print("Failed Decrypt")
return nil
}
return NSString(bytes: &plaintextBuffer, length: plaintextBufferSize, encoding: String.Encoding.utf8.rawValue)! as String
}
func getPublicKey() -> SecKey? {
return self.publicKey
}
func getPrivateKey() -> SecKey? {
return self.privateKey
}
I try to change UInt8 but when I do that error, what I must to do?
For encryption data use symmetric encryption such as AES, it is fast and does not have a size limitation.
If you really need to use an RSA (asymmetric) key pair use hybrid encryption where the data is encrypted with symmetric encryption and the symmetric is encrypted with asymmetric encryption, this is called hybrid encryption.
But as Luke states, just use HTTPS for encryption of data in transit.
only way Is that split string
this class for split.
extension String {
func splitByLength(_ length: Int) -> [String] {
var result = [String]()
var collectedCharacters = [Character]()
collectedCharacters.reserveCapacity(length)
var count = 0
for character in self.characters {
collectedCharacters.append(character)
count += 1
if (count == length) {
// Reached the desired length
count = 0
result.append(String(collectedCharacters))
collectedCharacters.removeAll(keepingCapacity: true)
}
}
// Append the remainder
if !collectedCharacters.isEmpty {
result.append(String(collectedCharacters))
}
return result
}
}
and then
let rsa : RSAWrapper? = RSAWrapper()
let success : Bool = (rsa?.generateKeyPair(keySize: 2048, privateTag: "com.atarmkplant", publicTag: "com.atarmkplant"))!
if (!success) {
print("Failed")
return
}
let test : String = "string more than 132 char "
let test2=test.splitByLength(132)
let tedadarrray = test2.count
var i = 0
var encryptionstring = ""
repeat {
let test3 = test2[i]
let encryption = rsa?.encryptBase64(text: test3)
encryptionstring = encryptionstring + encryption!
i = i + 1
} while i < tedadarrray
let decripArray = encryptionstring.splitByLength(349)
let tedadarrray2 = decripArray.count
var i2 = 0
var decripttionstring = ""
repeat {
print(i2 as Any)
let test3 : String = decripArray[i2]
let decription = rsa?.decpryptBase64(encrpted: test3)
decripttionstring = decripttionstring + decription!
i2 = i2 + 1
} while i2 < tedadarrray2
Im searching for encrypt and decrypt code in SWIFT.
But I cannot found a solution in SWIFT. I need pass a key to encrypt/decrypt in MD5 and convert to BASE64 in ECB mode!
I have this code in C#:
public static string MD5Cripto(string texto, string chave)
{
try
{
TripleDESCryptoServiceProvider sObCripto
= new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider sObjcriptoMd5 = new MD5CryptoServiceProvider();
byte[] sByteHash, sByteBuff;
string sTempKey = chave;
sByteHash = sObjcriptoMd5.ComputeHash(ASCIIEncoding
.UTF8.GetBytes(sTempKey));
sObjcriptoMd5 = null;
sObCriptografaSenha.Key = sByteHash;
sObCriptografaSenha.Mode = CipherMode.ECB;
sByteBuff = ASCIIEncoding.UTF8.GetBytes(texto);
return Convert.ToBase64String(sObCripto.CreateEncryptor()
.TransformFinalBlock(sByteBuff, 0, sByteBuff.Length));
}
catch (Exception ex)
{
return "Digite os valores Corretamente." + ex.Message;
}
}
UPDATE:
I try this but still not working.. What Im doing wrong? (Ignore my prints..)
func myEncrypt(encryptData:String) -> NSData?
{
let myKeyData : NSData = ("mykey" as NSString)
.dataUsingEncoding(NSUTF8StringEncoding)!
let myKeyDataMD5 = "mykey".md5()
let sArrayByte = myKeyDataMD5.hexToByteArray()
let myRawData : NSData = encryptData.dataUsingEncoding(NSUTF8StringEncoding)!
let buffer_size:size_t = myRawData.length + kCCBlockSize3DES
let 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)
let Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm,
options, sArrayByte, keyLength, nil,
myRawData.bytes, myRawData.length, buffer,
buffer_size, &num_bytes_encrypted)
if Int32(Crypto_status) == Int32(kCCSuccess)
{
let myResult: NSData = NSData(bytes: buffer, length: num_bytes_encrypted)
print("buffer")
let count = myResult.length / sizeof(UInt32)
var array = [UInt32](count: count, repeatedValue: 0)
myResult.getBytes(&array, length:count * sizeof(UInt32))
print(array)
free(buffer)
print("myResult")
print(myResult)
let resultNSString = NSString(data: myResult,
encoding: NSUnicodeStringEncoding)!
let resultString = resultNSString as String
print("resultString")
print(resultString)
let sBase64 = toBase64(String(resultString))
print("sBase64")
print(sBase64)
let data : NSData! = resultNSString
.dataUsingEncoding(NSUnicodeStringEncoding)
let count2 = data.length / sizeof(UInt32)
var array2 = [UInt32](count: count, repeatedValue: 0)
data.getBytes(&array2, length:count2 * sizeof(UInt32))
print("array2")
print(array2)
return myResult
}
else
{
free(buffer)
return nil
}
}
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.
I want to encrypt some files using AES256 in my cocoa application.
The resulting files should be as small as possible.
Here's my code:
static func encryptFile(pathToFile:String, destinationPath:String, key:String) -> Bool {
var error: NSError?
let fileContents = NSData(contentsOfFile: pathToFile, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &error)
if let fileContents = fileContents {
println("Trying to encrypt file \(pathToFile)")
let startTime = NSDate().timeIntervalSince1970
let encryptedContents = FileEncryptor.AES256Encryption(fileContents, key: key)
println("ENCRYPTION TIME: \(NSDate().timeIntervalSince1970 - startTime)")
if let encryptedContents = encryptedContents {
var writeError: NSError?
if (encryptedContents.writeToFile(pathToFile, options: NSDataWritingOptions.DataWritingAtomic, error: &writeError)) {
return true
} else {
if (writeError != nil) {
println("Cannot write to file \(pathToFile). Error: \(writeError)")
} else {
println("Cannot write to file \(pathToFile)")
}
return false
}
} else {
return false
}
} else {
println("Unable to read file \(pathToFile). Error: \(error)");
return false
}
}
static func AES256Encryption(dataToEncrypt:NSData, key:String) -> NSData? {
let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes)
print("keyLength = \(keyData.length), keyData = \(keyData)")
let dataLength = size_t(dataToEncrypt.length)
let dataBytes = UnsafeMutablePointer<Void>(dataToEncrypt.bytes)
print("dataLength = \(dataLength)")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCModeCBC)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
// let x: UInt = numBytesEncrypted
cryptData!.length = Int(numBytesEncrypted)
print("cryptLength = \(numBytesEncrypted)")
return cryptData
} else {
print("Error: \(cryptStatus)")
return nil
}
}
I have an issue with two things:
1. Encrypted file content look like [small part of the file]:
a56f 707a 24cb e965 08dd be3d 1a0d 9e7b
b73f c982 2014 fdae fa29 c63d 4588 ee29
7b03 5fb2 96a5 00be 2871 e3e8 af23 4eac
I would rather have it like:
ã.FrÚQ÷¬_ÄC¯Q%,™˜$žKÝôÙ„gC€È•GBvn&V9&´fÓ
I cannot decrypt some of the files.
Most of them are fine, however some are not. I've been looking for some kind of pattern, and the only thing I have found is that in most cases, the files which are correct, are larger when encrypted then they are when decrypted/original.
Here's a function I use to decrypt:
static func decryptFile(pathToFile:String, destinationPath:String, key:String) -> Bool {
var error: NSError?
let fileContents = NSData(contentsOfFile: pathToFile, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &error)
if let fileContents = fileContents {
println("Trying to decrypt file \(pathToFile)")
let startTime = NSDate().timeIntervalSince1970
let decryptedContents = FileEncryptor.AES256Decryption(fileContents, key: key)
println("DECRYPTION TIME: \(NSDate().timeIntervalSince1970 - startTime)")
return NSFileManager.defaultManager().createFileAtPath(destinationPath, contents:decryptedContents, attributes:nil)
} else {
println("Unable to read file \(pathToFile). Error: \(error)");
return false
}
}
static func AES256Decryption(data:NSData, key: String) -> NSData? {
let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes)
print("keyLength = \(keyData.length)")
let dataLength = size_t(data.length)
let dataBytes = UnsafeMutablePointer<Void>(data.bytes)
print("dataLength = \(dataLength), ")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCModeCBC)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
// let x: UInt = numBytesEncrypted
cryptData!.length = Int(numBytesEncrypted)
return cryptData
} else {
print("Error: \(cryptStatus)")
return nil
}
}
Almost all of the code has been taken from SO, it seems to work ok, apart from these issues I have.
The password I use is same for all of the files.
Any help will be appreciated!
EDIT:
About issue 2. It seems the code I used was prepared for ECB mode which I have changed to CBC. This means I have to increase size of the encrypted data. After making this change, almost all of the files work perfectly, apart from one... which worked ok when using the smaller value. Damn.