CryptoSwift + CryptoJS делает неправильный JSON в Swift 2.3

do {
let JSONObject:[String:String] = 
[
"username" : "username",
"password" : "Password",
"domain": "domain"
]
let my64data:NSData = NSData(base64EncodedString:Credentials.SecretKey, options: NSDataBase64DecodingOptions(rawValue: UInt(0)))!

let jsonData = try NSJSONSerialization.dataWithJSONObject(JSONObject, options: NSJSONWritingOptions.PrettyPrinted)

let myString = String(data: jsonData, encoding: NSUTF8StringEncoding)

    // let jsonString = AES1.encrypt(myString!, secretKey: Credentials.SecretKey, options:["iv":my64data])
    // print(" My Encrypted Json = \(jsonString)")
    //            
    // let Decrypt = AES1.decrypt(jsonString, secretKey: Credentials.SecretKey, options: ["iv":my64data])
    //print(" My Decrypted Json = \(Decrypt)")

let iv: Array<UInt8> = AES.randomIV(128/8)
let salt: Array<UInt8> = AES.randomIV(128/8)

let value = try! PKCS5.PBKDF2(password: Credentials.SecretKey.utf8.map({$0}), salt: salt, iterations: 1000, variant: .sha256).calculate()
                value.toHexString()

                _ = CryptoJS.mode.ECB()
                _ = CryptoJS.pad.Iso97971()
                _ = CryptoJS.pad.AnsiX923()
                _ = CryptoJS.pad.Iso10126()
                _ = CryptoJS.pad.ZeroPadding()

                let encrypted : Array<UInt8>

                     encrypted = try AES(key: value, iv: iv, blockMode: .CBC, padding: PKCS7()).encrypt((myString?.utf8.map({$0}))!)
                    let decrypted = try AES(key: value, iv: iv, blockMode: .CBC, padding: PKCS7()).decrypt(encrypted)

    //            let jsonString = AES1.encrypt(myString!, secretKey: String(value), options:["iv":iv.toHexString(),"mode":CryptoJS.mode().ECB,"padding":CryptoJS.pad().ZeroPadding])
                print(" My Encrypted Json = \(encrypted.toHexString())")
    //            
    //            let pkcs = PKCS7()
    //            
    //            let Decrypt = AES1.decrypt(jsonString, secretKey: String(value), options: ["iv":iv.toHexString(),"mode":CryptoJS.mode().ECB,"padding":pkcs])
               print(" My Decrypted Json = \(decrypted.toHexString())")

                let myInputIV : String = String(iv.toHexString())
                let myInputSalt :String = String(salt.toHexString())

                let finalJSONObject:[String:String] = [

                    "ciphertext" : "\(encrypted.toHexString())",
                    "iv" : "\(myInputIV)",
                    "salt": "\(myInputSalt)"

                ]

    print("Final Json Object = \(finalJSONObject)")

                let requestURL: NSURL = NSURL(string:"<myURL>")!
                print(requestURL)
                let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
                urlRequest.HTTPMethod = "POST"
                urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
                urlRequest.HTTPBody = try!NSJSONSerialization.dataWithJSONObject(finalJSONObject, options:.PrettyPrinted)

                let session = NSURLSession.sharedSession()
                let task = session.dataTaskWithRequest(urlRequest, completionHandler:{
                    data, response, error -> Void in

                    // Asynchronously call...
                    if (data != nil) {

                        print("Dataaa = \(data!)")

                        self.loginServiceResponse(data!)

                    }else{

                        Singleton.SharedInstance.myAlert(alertTitle:Constants.SERVER_ERROR_TITLE, alertMessage: Constants.SERVER_ERROR_MESSAGE, alertButtonTitle:Constants.OK)
                        self.activityIndicator.stopAnimating()

                    }


                })

                task.resume()

            } catch {
                print(error)

            }

У меня такая ошибка:

Ошибка с Json Error Domain = NSCocoaErrorDomain Code = 3840 «Недопустимое значение около символа 0». UserInfo = {NSDebugDescription = Недопустимое значение около символа 0.}


person Senthil    schedule 25.10.2016    source источник
comment
В почтальоне у меня ошибка заполнения   -  person Senthil    schedule 25.10.2016
comment
Лучше избегать использования CryptoSwift, среди прочего он в 500–1000 раз медленнее, чем реализации на основе Common Crypto. Common Crypto от Apple сертифицирован FIPS и, как таковой, был хорошо проверен, использование CryptoSwift дает шанс на правильность и безопасность.   -  person zaph    schedule 25.10.2016
comment
Обновите код с помощью минимального воспроизводимого примера, только часть шифрования с входами и выходами. Сначала включите простое шифрование, затем добавьте JSON, а затем добавьте сообщения. Постройте постепенно на рабочем коде, подход большого взрыва трудно отлаживать.   -  person zaph    schedule 25.10.2016
comment
Составные операторы, такие как AES(key: value, iv: iv, blockMode: .CBC, padding: PKCS7()).encrypt((myString?.utf8.map({$0}))!) и AES1.encrypt(myString!, secretKey: String(value), options:["iv":iv.toHexString(),"mode":CryptoJS.mode().ECB,"padding":CryptoJS.pad().ZeroPadding]), трудно понять и отладить, поскольку промежуточные значения недоступны. Несколько более простых операторов с промежуточной переменной проще и просто полагаются на компилятор для оптимизации кода. Читаемость кода - №1.   -  person zaph    schedule 25.10.2016
comment
@zaph: Есть ли у вас какие-нибудь общие советы по установке криптографии? Не могли бы вы помочь мне в этом   -  person Senthil    schedule 28.10.2016


Ответы (1)


Чтобы использовать Common Crypto от Swift

  1. Добавить мостовой заголовок
  2. Добавьте #import <CommonCrypto/CommonCrypto.h> в шапку.

В примере используется режим CBC и префиксы зашифрованных данных с IV, который является методом, обычно используемым для обработки IV.

Пример из раздела устаревшей документации:

Шифрование AES в режиме CBC со случайным IV (Swift 3.0)

Перед зашифрованными данными стоит префикс iv.

aesCBC128Encrypt создаст случайный IV с префиксом к зашифрованному коду.
aesCBC128Decrypt будет использовать префикс IV во время дешифрования.

Входы - это данные, а ключ - это объекты данных. Если закодированная форма, такая как Base64, при необходимости преобразовать в и / или из вызывающего метода.

Ключ должен иметь длину 128 бит (16 байтов), 192 бит (24 байта) или 256 бит (32 байта). Если используется другой размер ключа, будет выдана ошибка.

Заполнение PKCS # 7 установлено по умолчанию.

В этом примере требуется Common Crypto.
Необходимо иметь заголовок моста для проекта:
#import <CommonCrypto/CommonCrypto.h>
Добавьте Security.framework в проект.

Это пример, а не производственный код.

enum AESError: Error {
    case KeyError((String, Int))
    case IVError((String, Int))
    case CryptorError((String, Int))
}

// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data {
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) {
        throw AESError.KeyError(("Invalid key length", keyLength))
    }

    let ivSize = kCCBlockSizeAES128;
    let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
    var cryptData = Data(count:cryptLength)

    let status = cryptData.withUnsafeMutableBytes {ivBytes in
        SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
    }
    if (status != 0) {
        throw AESError.IVError(("IV generation failed", Int(status)))
    }

    var numBytesEncrypted :size_t = 0
    let options   = CCOptions(kCCOptionPKCS7Padding)

    let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            keyData.withUnsafeBytes {keyBytes in
                CCCrypt(CCOperation(kCCEncrypt),
                        CCAlgorithm(kCCAlgorithmAES),
                        options,
                        keyBytes, keyLength,
                        cryptBytes,
                        dataBytes, data.count,
                        cryptBytes+kCCBlockSizeAES128, cryptLength,
                        &numBytesEncrypted)
            }
        }
    }

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        cryptData.count = numBytesEncrypted + ivSize
    }
    else {
        throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
    }

    return cryptData;
}

// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? {
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) {
        throw AESError.KeyError(("Invalid key length", keyLength))
    }

    let ivSize = kCCBlockSizeAES128;
    let clearLength = size_t(data.count - ivSize)
    var clearData = Data(count:clearLength)

    var numBytesDecrypted :size_t = 0
    let options   = CCOptions(kCCOptionPKCS7Padding)

    let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            keyData.withUnsafeBytes {keyBytes in
                CCCrypt(CCOperation(kCCDecrypt),
                        CCAlgorithm(kCCAlgorithmAES128),
                        options,
                        keyBytes, keyLength,
                        dataBytes,
                        dataBytes+kCCBlockSizeAES128, clearLength,
                        cryptBytes, clearLength,
                        &numBytesDecrypted)
            }
        }
    }

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        clearData.count = numBytesDecrypted
    }
    else {
        throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
    }
    
    return clearData;
}

Пример использования:

let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData   = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData:   \(clearData as NSData)")
print("keyData:     \(keyData as NSData)")

var cryptData :Data?
do {
    cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
    print("cryptData:   \(cryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCEncrypt: \(status)")
}

let decryptData :Data?
do {
    let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
    print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCDecrypt: \(status)")
}

Пример вывода:

clearData:   <636c6561 72446174 61303132 33343536>
keyData:     <6b657944 61746138 39303132 33343536>
cryptData:   <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>

Примечания:
Одна из типичных проблем с примером кода режима CBC заключается в том, что он оставляет создание и совместное использование случайного IV пользователю. Этот пример включает создание IV, префикса зашифрованных данных и использование префикса IV во время дешифрования. Это освобождает случайного пользователя от деталей, необходимых для режима CBC. .

В целях безопасности зашифрованные данные также должны иметь аутентификацию, в этом примере кода этого не предусмотрено, чтобы они были небольшими и обеспечивали лучшую совместимость для других платформ.

Также отсутствует ключевой вывод ключа из пароля, рекомендуется использовать PBKDF2, текстовые пароли используются в качестве ключевого материала.

Для получения надежного готового к эксплуатации мультиплатформенного кода шифрования см. RNCryptor.

person zaph    schedule 28.10.2016