Error when decoding certain Base64 strings, but not others - ios

To keep this simple, I'll only be encoding/decoding a single byte.
If I encode the byte 127, I get the base64 string "fw==" which can be successfully decoded back to byte 127. If, however, I encode a byte ≥ 128, then even though I can produce a base64 string without error (for example, byte 128 gives the string "gA=="), I get an error when I try to decode it.
Here's my code which can be copy-pasted into any Xcode playground to reproduce the problem:
func stringToByteArray(string: String) -> [UInt8] {
var bytes: [UInt8] = [];
for code in string.utf8 {
bytes.append(UInt8(code));
}
return bytes;
}
func byteArrayToBase64(bytes: [UInt8]) -> String {
let nsdata: NSData = NSData(bytes: bytes as [Byte], length: bytes.count)
let base64Encoded: NSString = nsdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0));
return String(base64Encoded);
}
func base64ToByteArray(base64String: String) -> [UInt8] {
let nsdata: NSData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))!
let base64Decoded: NSString = NSString(data: nsdata, encoding: NSUTF8StringEncoding)!
return stringToByteArray(String(base64Decoded));
}
/* Replacing 127 with 128 below or greater produces an error */
var testString = byteArrayToBase64([127]);
base64ToByteArray(testString)

The problem is here:
let base64Decoded: NSString = NSString(data: nsdata, encoding: NSUTF8StringEncoding)!
You convert the decoded data to a string. This fails for
[128] because that does not represent a valid UTF-8 sequence.
Here is a version that avoids the intermediate string:
func base64ToByteArray(base64String: String) -> [UInt8] {
let nsdata: NSData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))!
// Create array of the required size ...
var bytes = [UInt8](count: nsdata.length, repeatedValue: 0)
// ... and fill it with the data
nsdata.getBytes(&bytes)
return bytes
}
Remarks:
options: NSDataBase64DecodingOptions(rawValue: 0) can be simplified
to options: nil.
There are some unnecessary type annotations and conversions in your code.
Your function crashes if baseString is not a valid Base64 string.
You could change it to return an optional.
Then it would look like this:
func byteArrayToBase64(bytes: [UInt8]) -> String {
let nsdata = NSData(bytes: bytes, length: bytes.count)
let base64Encoded = nsdata.base64EncodedStringWithOptions(nil);
return base64Encoded;
}
func base64ToByteArray(base64String: String) -> [UInt8]? {
if let nsdata = NSData(base64EncodedString: base64String, options: nil) {
var bytes = [UInt8](count: nsdata.length, repeatedValue: 0)
nsdata.getBytes(&bytes)
return bytes
}
return nil // Invalid input
}
Example usage:
let testString = byteArrayToBase64([127, 128, 0, 130]);
println(testString) // Output: f4AAgg==
if let result = base64ToByteArray(testString) {
println(result) // Output: [127, 128, 0, 130]
} else {
println("failed")
}
Update for Swift 2 / Xcode 7:
func byteArrayToBase64(bytes: [UInt8]) -> String {
let nsdata = NSData(bytes: bytes, length: bytes.count)
let base64Encoded = nsdata.base64EncodedStringWithOptions([]);
return base64Encoded;
}
func base64ToByteArray(base64String: String) -> [UInt8]? {
if let nsdata = NSData(base64EncodedString: base64String, options: []) {
var bytes = [UInt8](count: nsdata.length, repeatedValue: 0)
nsdata.getBytes(&bytes, length: bytes.count)
return bytes
}
return nil // Invalid input
}
let testString = byteArrayToBase64([127, 128, 0, 130]);
print(testString) // Output: f4AAgg==
if let result = base64ToByteArray(testString) {
print(result) // Output: [127, 128, 0, 130]
} else {
print("failed")
}
Update for Swift 3 and later:
func byteArrayToBase64(bytes: [UInt8]) -> String {
let data = Data(bytes)
let base64Encoded = data.base64EncodedString()
return base64Encoded;
}
func base64ToByteArray(base64String: String) -> [UInt8]? {
guard let data = Data(base64Encoded: base64String) else {
return nil
}
return Array(data)
}
let testString = byteArrayToBase64(bytes: [127, 128, 0, 130]);
print(testString) // Output: f4AAgg==
if let result = base64ToByteArray(base64String: testString) {
print(result) // Output: [127, 128, 0, 130]
} else {
print("failed")
}

Related

Argument type 'SecretSpec' does not conform to expected type 'Sequence'

I want to encrypt a message on playground. my code is given below. i write another class to generate a secretkey. when convert the secret key into string, it gives error.
import UIKit
import Foundation
import CommonCrypto
class SecretSpec {
var algorithm: String = "AES/ECB/PKCS5padding"
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, options:Int = (kCCOptionECBMode + 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,
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 mdT = "YourStrongKeyasdfghjklzxcvbnm"
var algorithm: String = "AES/ECB/PKCS7padding"
var s = MD5(mdT)
let buf: [UInt8] = Array(s!.utf8)
var skcSpec = SecretSpec()
skcSpec.SecretSpec(key: buf, algorithm: algorithm)
print("hello: \(skcSpec)")
skcSpec.getEncoded()
skcSpec.getFormat()
skcSpec.getAlgorithm()
skcSpec.hashCode()
let msg: NSMutableDictionary = NSMutableDictionary()
msg.setValue("uttam kumar", forKey: "name")
msg.setValue("1001", forKey: "id")
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 skc = String(data: Data(skcSpec), encoding: .utf8)!
var encoded = msgStr.aesEncrypt(key: String(skc))!
print("encoded: \(encoded)")
I want to get String value of 'skc'. and print it. but it gives 'Argument type 'SecretSpec' does not conform to expected type 'Sequence'' error. please help me.
Data does not have an initialiser for your custom type. Did you mean to get the encoded value?
var skc = String(data: Data(skcSpec.getEncoded()), encoding: .utf8)!

DES Encryption and decryption algorithm in swift

I am trying to use DES algorithm for Encryption and decryption in swift
But with the code that I have written the encrypted message is changing for every build
Here is my code:
import UIKit
import CommonCrypto
public class IAppEncryptionUtitlity: NSObject {
private override init(){}
public static let sharedNetworkVar: IAppEncryptionUtitlity = IAppEncryptionUtitlity()
let key = IAppConfig.key
func myEncrypt(encryptData:String) -> NSData?{
var myKeyData : NSData = ("DyfmgL9p" as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData
var myRawData : NSData = encryptData.data(using: String.Encoding.utf8)! as NSData
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>.allocate(capacity: 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)
print("my result \(myResult)") //This just prints the data
let keyData: NSData = myResult
let hexString = keyData.hexEncodedString()
print("hex result \(keyData)") // I needed a hex string output
//myDecrypt(decryptData: 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).data(using: String.Encoding.utf8.rawValue)! as NSData
var buffer_size : size_t = mydata_len+kCCBlockSizeAES128
var buffer = UnsafeMutablePointer<NSData>.allocate(capacity: 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(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)
print("decrypt \(myResult)")
var stringResult = NSString(data: myResult as Data, encoding:String.Encoding.utf8.rawValue)
print("my decrypt string \(stringResult!)")
return myResult
}else{
free(buffer)
return nil
}
}
}
extension NSData {
struct HexEncodingOptions: OptionSet {
let rawValue: Int
static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
}
func hexEncodedString(options: HexEncodingOptions = []) -> String {
let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
//var map = { String(format: format, $0) }.joined()
return ""
}
}
Output is changing for every build . Whats wrong in the code or
And is kCCOptionPKCS7Padding and kCCOptionPKCS5Padding is same?
Thanks In advance
Got Solution by changing the code
import UIKit
import CommonCrypto
var message: String?
public class IAppEncryptionUtitlity: NSObject {
//Calling method to encrypt using extensions
public func methodToCallEncryption( stringToEncrypt : String ) ->String {
let iVValue:String = "nzug8FrX"
let keyValue = IAppConfig.key //DyfmgL9p
let encoded = stringToEncrypt.desEncrypt( key : keyValue , iv : iVValue )
return encoded!
}
public func methodToCallDecryption( stringToDecrypt : String ) -> String{
let iVValue:String = "nzug8FrX"
let keyValue = IAppConfig.key //DyfmgL9p
let decoded = stringToDecrypt.desEncrypt( key : keyValue , iv : iVValue )
return decoded!
}
}
extension String {
func desEncrypt(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)) + kCCBlockSizeDES) {
let keyLength = size_t(kCCKeySizeDES)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmDES)
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 desDecrypt(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)) + kCCBlockSizeDES) {
let keyLength = size_t(kCCKeySizeDES)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmDES)
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
}
}
Thanks everyone for the help
We can use a String category like shown below for all symmetric encryption and decryption including DES, 3DES, and AES.
/// Extension for Symmetric Encryption and Decryption with DES, 3DES, AES algorithms
extension String {
/// Encrypts message with DES algorithm
func desEncrypt(key:String) -> String? {
return symetricEncrypt(key: key, blockSize: kCCBlockSizeDES, keyLength: size_t(kCCKeySizeDES), algorithm: UInt32(kCCAlgorithmDES))
}
/// Encrypts message with 3DES algorithm
func tripleDesEncrypt(key:String) -> String? {
return symetricEncrypt(key: key, blockSize: kCCBlockSize3DES, keyLength: size_t(kCCKeySize3DES), algorithm: UInt32(kCCAlgorithm3DES))
}
/// Encrypts message with AES 128 algorithm
func aes128Encrypt(key:String) -> String? {
return symetricEncrypt(key: key, blockSize: kCCBlockSizeAES128, keyLength: size_t(kCCKeySizeAES128), algorithm: UInt32(kCCAlgorithmAES128))
}
/// Encrypts message with AES algorithm
func aesEncrypt(key:String) -> String? {
return symetricEncrypt(key: key, blockSize: kCCBlockSizeAES128, keyLength: size_t(kCCKeySizeAES256), algorithm: UInt32(kCCAlgorithmAES))
}
/// Encrypts a message with symmetric algorithm
func symetricEncrypt(key:String, blockSize: Int, keyLength: size_t, algorithm: CCAlgorithm, options: Int = kCCOptionPKCS7Padding) -> String? {
let keyData = key.data(using: String.Encoding.utf8)! as NSData
let data = self.data(using: String.Encoding.utf8)! as NSData
let cryptData = NSMutableData(length: Int(data.length) + blockSize)!
let operation: CCOperation = UInt32(kCCEncrypt)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algorithm,
UInt32(options),
keyData.bytes, keyLength,
nil,
data.bytes, data.length,
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
}
}
/// Decrypts message with DES algorithm
func desDecrypt(key:String) -> String? {
return symetricDecrypt(key: key, blockSize: kCCBlockSizeDES, keyLength: size_t(kCCKeySizeDES), algorithm: UInt32(kCCAlgorithmDES))
}
/// Decrypts message with 3DES algorithm
func tripleDesDecrypt(key:String) -> String? {
return symetricDecrypt(key: key, blockSize: kCCBlockSize3DES, keyLength: size_t(kCCKeySize3DES), algorithm: UInt32(kCCAlgorithm3DES))
}
/// Decrypts message with AES 128 algorithm
func aes128Decrypt(key:String) -> String? {
return symetricDecrypt(key: key, blockSize: kCCBlockSizeAES128, keyLength: size_t(kCCKeySizeAES128), algorithm: UInt32(kCCAlgorithmAES128))
}
/// Decrypts message with AES algorithm
func aesDecrypt(key:String) -> String? {
return symetricDecrypt(key: key, blockSize: kCCBlockSizeAES128, keyLength: size_t(kCCKeySizeAES256), algorithm: UInt32(kCCAlgorithmAES))
}
/// Decrypts a message with symmetric algorithm
func symetricDecrypt(key:String, blockSize: Int, keyLength: size_t, algorithm: CCAlgorithm, 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)) + blockSize) {
let operation: CCOperation = UInt32(kCCDecrypt)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algorithm,
UInt32(options),
(keyData as NSData).bytes, keyLength,
nil,
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
}
}
Full source:
https://gist.github.com/tharindu/1cf0201492e41f1c287e51abb02902cd

Sha 256 Encryption syntax error in swift 3.0

func SHA256() -> String {
let data = self.data(using: String.Encoding.utf8)
let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH))
CC_SHA256((data! as NSData).bytes, CC_LONG(data!.count), UnsafeMutablePointer(res!.mutableBytes))
let hashedString = "\(res!)".replacingOccurrences(of: "", with: "").replacingOccurrences(of: " ", with: "")
let badchar: CharacterSet = CharacterSet(charactersIn: "\"<\",\">\"")
let cleanedstring: String = (hashedString.components(separatedBy: badchar) as NSArray).componentsJoined(by: "")
return cleanedstring
}
I am using this function to encrypt strings it was working fine in swift 2,
now its not working in swift 3.0
Perfect solution Swift 3+:
extension String {
// MARK: - SHA256
func get_sha256_String() -> String {
guard let data = self.data(using: .utf8) else {
print("Data not available")
return ""
}
return getHexString(fromData: digest(input: data as NSData))
}
private func digest(input : NSData) -> NSData {
let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
var hashValue = [UInt8](repeating: 0, count: digestLength)
CC_SHA256(input.bytes, UInt32(input.length), &hashValue)
return NSData(bytes: hashValue, length: digestLength)
}
private func getHexString(fromData data: NSData) -> String {
var bytes = [UInt8](repeating: 0, count: data.length)
data.getBytes(&bytes, length: data.length)
var hexString = ""
for byte in bytes {
hexString += String(format:"%02x", UInt8(byte))
}
return hexString
}
}
How to use:
let desiredSHA256 = "yourString".get_sha256_String()
func sha256(string: String) -> Data? {
guard let messageData = string.data(using:String.Encoding.utf8) else { return nil; }
var digestData = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
_ = digestData.withUnsafeMutableBytes {digestBytes in
messageData.withUnsafeBytes {messageBytes in
CC_SHA256(messageBytes, CC_LONG(messageData.count), digestBytes)
}
}
return digestData
}
Example:
let testString = "sha me"
print("testString: \(testString)")
let shaData = sha256(string: testString)
let shaHex = shaData!.map { String(format: "%02hhx", $0) }.joined()
print("shaHex: \(shaHex)")
Output:
testString: sha me
shaData: a60e0eee 30a3a4f1 c4f8b93f 16ad22cb 0339447b 1653f331 edbda55f eee00789
What is new is the .withUnsafeMutableBytes closure.
func SHA256() -> String {
let data = self.data(using: String.Encoding.utf8)
let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH))
CC_SHA256(((data! as NSData)).bytes, CC_LONG(data!.count), res?.mutableBytes.assumingMemoryBound(to: UInt8.self))
let hashedString = "\(res!)".replacingOccurrences(of: "", with: "").replacingOccurrences(of: " ", with: "")
let badchar: CharacterSet = CharacterSet(charactersIn: "\"<\",\">\"")
let cleanedstring: String = (hashedString.components(separatedBy: badchar) as NSArray).componentsJoined(by: "")
return cleanedstring
}
Replaced CC_SHA256((data! as NSData).bytes, CC_LONG(data!.count), UnsafeMutablePointer(res!.mutableBytes))

How read text file on server?

I use this code to read a local text file, it's work!
class StreamReader {
let encoding : UInt
let chunkSize : Int
var fileHandle : NSFileHandle!
let buffer : NSMutableData!
let delimData : NSData!
var atEof : Bool = false
init?(path: String, delimiter: String = "\n", encoding : UInt = NSUTF8StringEncoding, chunkSize : Int = 4096) {
self.chunkSize = chunkSize
self.encoding = encoding
if let fileHandle = NSFileHandle(forReadingAtPath: path),
delimData = delimiter.dataUsingEncoding(encoding),
buffer = NSMutableData(capacity: chunkSize)
{
self.fileHandle = fileHandle
self.delimData = delimData
self.buffer = buffer
} else {
self.fileHandle = nil
self.delimData = nil
self.buffer = nil
return nil
}
}
deinit {
self.close()
}
/// Return next line, or nil on EOF.
func nextLine() -> String? {
precondition(fileHandle != nil, "Attempt to read from closed file")
if atEof {
return nil
}
// Read data chunks from file until a line delimiter is found:
var range = buffer.rangeOfData(delimData, options: nil, range: NSMakeRange(0, buffer.length))
while range.location == NSNotFound {
let tmpData = fileHandle.readDataOfLength(chunkSize)
if tmpData.length == 0 {
// EOF or read error.
atEof = true
if buffer.length > 0 {
// Buffer contains last line in file (not terminated by delimiter).
let line = NSString(data: buffer, encoding: encoding)
buffer.length = 0
return line as String?
}
// No more lines.
return nil
}
buffer.appendData(tmpData)
range = buffer.rangeOfData(delimData, options: nil, range: NSMakeRange(0, buffer.length))
}
// Convert complete line (excluding the delimiter) to a string:
let line = NSString(data: buffer.subdataWithRange(NSMakeRange(0, range.location)),
encoding: encoding)
// Remove line (and the delimiter) from the buffer:
buffer.replaceBytesInRange(NSMakeRange(0, range.location + range.length), withBytes: nil, length: 0)
return line as String?
}
/// Start reading from the beginning of file.
func rewind() -> Void {
fileHandle.seekToFileOffset(0)
buffer.length = 0
atEof = false
}
/// Close the underlying file. No reading must be done after calling this method.
func close() -> Void {
fileHandle?.closeFile()
fileHandle = nil
}
}
Usage
var path_up1 = "/Users/rrr/Desktop/up/1.txt"
if let aStreamReader = StreamReader(path: path_up1) {
while let line = aStreamReader.nextLine() {
println(line)
}
}
But I have to read a file on the server (ex: http://www.1111.com/1.txt).
Help me, plz!
You can read the file directly via NSURLConnection
let url = NSURL(string:"http://www.1111.com/1.txt")!
let request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.currentQueue()) { (response, data, error) -> Void in
if error != nil {
println(error!)
} else {
if let textFile = NSString(data: data, encoding: NSUTF8StringEncoding) {
println(textFile)
}
}
}
The example assumes that the text file is UTF-8 encoded.
Or if you want to read the data sequentially implement the delegate methods of NSURLConnection and use init?(request:delegate:startImmediately:)

AES Encrypt and Decrypt

I write an application by swift, i need AES Encrypt and Decrypt functionality, i received encrypted data from another .Net solution, but i can't find something to do it.
This is my .net Encryption:
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
I need to decrypt function in swift.
CryptoSwift Example
Updated to Swift 2
import Foundation
import CryptoSwift
extension String {
func aesEncrypt(key: String, iv: String) throws -> String{
let data = self.dataUsingEncoding(NSUTF8StringEncoding)
let enc = try AES(key: key, iv: iv, blockMode:.CBC).encrypt(data!.arrayOfBytes(), padding: PKCS7())
let encData = NSData(bytes: enc, length: Int(enc.count))
let base64String: String = encData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0));
let result = String(base64String)
return result
}
func aesDecrypt(key: String, iv: String) throws -> String {
let data = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions(rawValue: 0))
let dec = try AES(key: key, iv: iv, blockMode:.CBC).decrypt(data!.arrayOfBytes(), padding: PKCS7())
let decData = NSData(bytes: dec, length: Int(dec.count))
let result = NSString(data: decData, encoding: NSUTF8StringEncoding)
return String(result!)
}
}
Usage:
let key = "bbC2H19lkVbQDfakxcrtNMQdd0FloLyw" // length == 32
let iv = "gqLOHUioQ0QjhuvI" // length == 16
let s = "string to encrypt"
let enc = try! s.aesEncrypt(key, iv: iv)
let dec = try! enc.aesDecrypt(key, iv: iv)
print(s) // string to encrypt
print("enc:\(enc)") // 2r0+KirTTegQfF4wI8rws0LuV8h82rHyyYz7xBpXIpM=
print("dec:\(dec)") // string to encrypt
print("\(s == dec)") // true
Make sure you have the right length of iv (16) and key (32) then you won't hit "Block size and Initialization Vector must be the same length!" error.
CryptoSwift Example
Updated SWIFT 4.*
func aesEncrypt() throws -> String {
let encrypted = try AES(key: KEY, iv: IV, padding: .pkcs7).encrypt([UInt8](self.data(using: .utf8)!))
return Data(encrypted).base64EncodedString()
}
func aesDecrypt() throws -> String {
guard let data = Data(base64Encoded: self) else { return "" }
let decrypted = try AES(key: KEY, iv: IV, padding: .pkcs7).decrypt([UInt8](data))
return String(bytes: decrypted, encoding: .utf8) ?? self
}
Code provided by SHS didn't work for me, but this one apparently did (I used a Bridging Header: #import <CommonCrypto/CommonCrypto.h>):
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
}
}
From my ViewController:
let encoded = message.aesEncrypt(key: keyString, iv: iv)
let unencode = encoded?.aesDecrypt(key: keyString, iv: iv)
There is an interesting "pure-swift" Open Source library:
CryptoSwift: https://github.com/krzyzanowskim/CryptoSwift
It supports: AES-128, AES-192, AES-256, ChaCha20
Example with AES decrypt (got from project README.md file):
import CryptoSwift
let setup = (key: keyData, iv: ivData)
let decryptedAES = AES(setup).decrypt(encryptedData)
I was using CommonCrypto to generate Hash through the code of MihaelIsaev/HMAC.swift from Easy to use Swift implementation of CommonCrypto HMAC. This implementation is without using Bridging-Header, with creation of Module file.
Now to use AESEncrypt and Decrypt, I directly added the functions inside "extension String {" in HAMC.swift.
func aesEncrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
if let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
data = self.dataUsingEncoding(NSUTF8StringEncoding),
cryptData = NSMutableData(length: Int((data.length)) + 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.bytes, keyLength,
iv,
data.bytes, data.length,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let base64cryptString = cryptData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
return base64cryptString
}
else {
return nil
}
}
return nil
}
func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
if let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
data = NSData(base64EncodedString: self, options: .IgnoreUnknownCharacters),
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.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, encoding:NSUTF8StringEncoding)
return unencryptedMessage
}
else {
return nil
}
}
return nil
}
The functions were taken from RNCryptor. It was an easy addition in the hashing functions and in one single file "HMAC.swift", without using Bridging-header. I hope this will be useful for developers in swift requiring Hashing and AES Encryption/Decryption.
Example of using the AESDecrypt as under.
let iv = "AA-salt-BBCCDD--" // should be of 16 characters.
//here we are convert nsdata to String
let encryptedString = String(data: dataFromURL, encoding: NSUTF8StringEncoding)
//now we are decrypting
if let decryptedString = encryptedString?.aesDecrypt("12345678901234567890123456789012", iv: iv) // 32 char pass key
{
// Your decryptedString
}
CryptoSwift is very interesting project but for now it has some AES speed limitations. Be carefull if you need to do some serious crypto - it might be worth to go through the pain of bridge implemmenting CommonCrypto.
BigUps to Marcin for pureSwift implementation
You can use CommonCrypto from iOS or CryptoSwift as external library. There are implementations with both tools below. That said, CommonCrypto output with AES should be tested, as it is not clear in CC documentation, which mode of AES it uses.
CommonCrypto in Swift 4.2
import CommonCrypto
func encrypt(data: Data) -> Data {
return cryptCC(data: data, key: key, operation: kCCEncrypt)
}
func decrypt(data: Data) -> Data {
return cryptCC(data: data, key: key, operation: kCCDecrypt)
}
private func cryptCC(data: Data, key: String operation: Int) -> Data {
guard key.count == kCCKeySizeAES128 else {
fatalError("Key size failed!")
}
var ivBytes: [UInt8]
var inBytes: [UInt8]
var outLength: Int
if operation == kCCEncrypt {
ivBytes = [UInt8](repeating: 0, count: kCCBlockSizeAES128)
guard kCCSuccess == SecRandomCopyBytes(kSecRandomDefault, ivBytes.count, &ivBytes) else {
fatalError("IV creation failed!")
}
inBytes = Array(data)
outLength = data.count + kCCBlockSizeAES128
} else {
ivBytes = Array(Array(data).dropLast(data.count - kCCBlockSizeAES128))
inBytes = Array(Array(data).dropFirst(kCCBlockSizeAES128))
outLength = inBytes.count
}
var outBytes = [UInt8](repeating: 0, count: outLength)
var bytesMutated = 0
guard kCCSuccess == CCCrypt(CCOperation(operation), CCAlgorithm(kCCAlgorithmAES128), CCOptions(kCCOptionPKCS7Padding), Array(key), kCCKeySizeAES128, &ivBytes, &inBytes, inBytes.count, &outBytes, outLength, &bytesMutated) else {
fatalError("Cryptography operation \(operation) failed")
}
var outData = Data(bytes: &outBytes, count: bytesMutated)
if operation == kCCEncrypt {
ivBytes.append(contentsOf: Array(outData))
outData = Data(bytes: ivBytes)
}
return outData
}
CryptoSwift v0.14 in Swift 4.2
enum Operation {
case encrypt
case decrypt
}
private let keySizeAES128 = 16
private let aesBlockSize = 16
func encrypt(data: Data, key: String) -> Data {
return crypt(data: data, key: key, operation: .encrypt)
}
func decrypt(data: Data, key: String) -> Data {
return crypt(data: data, key: key, operation: .decrypt)
}
private func crypt(data: Data, key: String, operation: Operation) -> Data {
guard key.count == keySizeAES128 else {
fatalError("Key size failed!")
}
var outData: Data? = nil
if operation == .encrypt {
var ivBytes = [UInt8](repeating: 0, count: aesBlockSize)
guard 0 == SecRandomCopyBytes(kSecRandomDefault, ivBytes.count, &ivBytes) else {
fatalError("IV creation failed!")
}
do {
let aes = try AES(key: Array(key.data(using: .utf8)!), blockMode: CBC(iv: ivBytes))
let encrypted = try aes.encrypt(Array(data))
ivBytes.append(contentsOf: encrypted)
outData = Data(bytes: ivBytes)
} catch {
print("Encryption error: \(error)")
}
} else {
let ivBytes = Array(Array(data).dropLast(data.count - aesBlockSize))
let inBytes = Array(Array(data).dropFirst(aesBlockSize))
do {
let aes = try AES(key: Array(key.data(using: .utf8)!), blockMode: CBC(iv: ivBytes))
let decrypted = try aes.decrypt(inBytes)
outData = Data(bytes: decrypted)
} catch {
print("Decryption error: \(error)")
}
}
return outData!
}
Swift4:
let key = "ccC2H19lDDbQDfakxcrtNMQdd0FloLGG" // length == 32
let iv = "ggGGHUiDD0Qjhuvv" // length == 16
func encryptFile(_ path: URL) -> Bool{
do{
let data = try Data.init(contentsOf: path)
let encodedData = try data.aesEncrypt(key: key, iv: iv)
try encodedData.write(to: path)
return true
}catch{
return false
}
}
func decryptFile(_ path: URL) -> Bool{
do{
let data = try Data.init(contentsOf: path)
let decodedData = try data.aesDecrypt(key: key, iv: iv)
try decodedData.write(to: path)
return true
}catch{
return false
}
}
Install CryptoSwift
import CryptoSwift
extension Data {
func aesEncrypt(key: String, iv: String) throws -> Data{
let encypted = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .pkcs7).encrypt(self.bytes)
return Data(bytes: encypted)
}
func aesDecrypt(key: String, iv: String) throws -> Data {
let decrypted = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .pkcs7).decrypt(self.bytes)
return Data(bytes: decrypted)
}
}
Update Swift 4.2
Here, for instance, we encrypt a string to base64encoded string. And then we decrypt the same to a readable string. (That would be same as our input string).
In my case, I use this to encrypt a string and embed that to QR Code. Then another party scan that and decrypt the same. So intermediate won't understand the QR codes.
Step 1: Encrypt a string "Encrypt My Message 123"
Step 2: Encrypted base64Encoded string : +yvNjiD7F9/JKmqHTc/Mjg== (The same printed on QR code)
Step 3: Scan and decrypt the string "+yvNjiD7F9/JKmqHTc/Mjg=="
Step 4: It comes final result - "Encrypt My Message 123"
Functions for Encrypt & Decrypt:
func encryption(stringToEncrypt: String) -> String{
let key = "MySecretPKey"
//let iv = "92c9d2c07a9f2e0a"
let data = stringToEncrypt.data(using: .utf8)
let keyD = key.data(using: .utf8)
let encr = (data as NSData?)!.aes128EncryptedData(withKey: keyD)
let base64String: String = (encr as NSData?)!.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
print(base64String)
return base64String
}
func decryption(encryptedString:String) -> String{
let key = "MySecretPKey"
//let iv = "92c9d2c07a9f2e0a"
let keyD = key.data(using: .utf8)
let decrpStr = NSData(base64Encoded: encryptedString, options: NSData.Base64DecodingOptions(rawValue: 0))
let dec = (decrpStr)!.aes128DecryptedData(withKey: keyD)
let backToString = String(data: dec!, encoding: String.Encoding.utf8)
print(backToString!)
return backToString!
}
Usage:
let enc = encryption(stringToEncrypt: "Encrypt My Message 123")
let decryptedString = decryption(encryptedString: enc)
print(decryptedString)
Classes for supporting AES encrypting functions, these are written in Objective-C. So for swift, you need to use bridge header to support these.
Class Name: NSData+AES.h
#import <Foundation/Foundation.h>
#interface NSData (AES)
- (NSData *)AES128EncryptedDataWithKey:(NSData *)key;
- (NSData *)AES128DecryptedDataWithKey:(NSData *)key;
- (NSData *)AES128EncryptedDataWithKey:(NSData *)key iv:(NSData *)iv;
- (NSData *)AES128DecryptedDataWithKey:(NSData *)key iv:(NSData *)iv;
#end
Class Name: NSData+AES.m
#import "NSData+AES.h"
#import <CommonCrypto/CommonCryptor.h>
#implementation NSData (AES)
- (NSData *)AES128EncryptedDataWithKey:(NSData *)key
{
return [self AES128EncryptedDataWithKey:key iv:nil];
}
- (NSData *)AES128DecryptedDataWithKey:(NSData *)key
{
return [self AES128DecryptedDataWithKey:key iv:nil];
}
- (NSData *)AES128EncryptedDataWithKey:(NSData *)key iv:(NSData *)iv
{
return [self AES128Operation:kCCEncrypt key:key iv:iv];
}
- (NSData *)AES128DecryptedDataWithKey:(NSData *)key iv:(NSData *)iv
{
return [self AES128Operation:kCCDecrypt key:key iv:iv];
}
- (NSData *)AES128Operation:(CCOperation)operation key:(NSData *)key iv:(NSData *)iv
{
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(operation,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding | kCCOptionECBMode,
key.bytes,
kCCBlockSizeAES128,
iv.bytes,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
#end
I found the solution, it is a good library.
Cross platform 256bit AES encryption / decryption.
This project contains the implementation of 256 bit AES encryption which works on all the platforms (C#, iOS, Android). One of the key objective is to make AES work on all the platforms with simple implementation.
Platforms Supported:
iOS ,
Android ,
Windows (C#).
https://github.com/Pakhee/Cross-platform-AES-encryption
This is a pretty old post but XCode 10 added the CommonCrypto module so you don't need a module map. Also with Swift 5, no need for the annoying casts.
You could do something like:
func decrypt(_ data: Data, iv: Data, key: Data) throws -> String {
var buffer = [UInt8](repeating: 0, count: data.count + kCCBlockSizeAES128)
var bufferLen: Int = 0
let status = CCCrypt(
CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES128),
CCOptions(kCCOptionPKCS7Padding),
[UInt8](key),
kCCBlockSizeAES128,
[UInt8](iv),
[UInt8](data),
data.count,
&buffer,
buffer.count,
&bufferLen
)
guard status == kCCSuccess,
let str = String(data: Data(bytes: buffer, count: bufferLen),
encoding: .utf8) else {
throw NSError(domain: "AES", code: -1, userInfo: nil)
}
return str
}
You can just copy & paste these methods (Swift 4+):
class func encryptMessage(message: String, encryptionKey: String, iv: String) -> String? {
if let aes = try? AES(key: encryptionKey, iv: iv),
let encrypted = try? aes.encrypt(Array<UInt8>(message.utf8)) {
return encrypted.toHexString()
}
return nil
}
class func decryptMessage(encryptedMessage: String, encryptionKey: String, iv: String) -> String? {
if let aes = try? AES(key: encryptionKey, iv: iv),
let decrypted = try? aes.decrypt(Array<UInt8>(hex: encryptedMessage)) {
return String(data: Data(bytes: decrypted), encoding: .utf8)
}
return nil
}
Example:
let encryptMessage = encryptMessage(message: "Hello World!", encryptionKey: "mykeymykeymykey1", iv: "myivmyivmyivmyiv")
// Output of encryptMessage is: 649849a5e700d540f72c4429498bf9f4
let decryptedMessage = decryptMessage(encryptedMessage: encryptMessage, encryptionKey: "mykeymykeymykey1", iv: "myivmyivmyivmyiv")
// Output of decryptedMessage is: Hello World!
Don't forget encryptionKey & iv should be 16 bytes.

Resources