【问题标题】:using TripleDes and MD5 in swift快速使用 TripleDes 和 MD5
【发布时间】:2016-11-30 11:41:59
【问题描述】:

我有一个使用tripleDes 和MD5 的java 代码算法。有我的java代码:

 private String _encrypt(String message, String secretKey) throws Exception {

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 16);

        SecretKey key = new SecretKeySpec(keyBytes, "DESede/ECB/PKCS7Padding");
        Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS7Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] plainTextBytes = message.getBytes("utf-8");


        byte[] buf = cipher.doFinal(plainTextBytes);
        byte [] base64Bytes = Base64.encodeBase64(buf);
        String base64EncryptedString = new String(base64Bytes);

        return base64EncryptedString;
    }

我想在 swift 中使用 TripleDes 和 MD5,我正在将此 java 代码转换为 swift,但在 swift 中存在问题,因为在 java 中使用 16 字节而 swift 使用 24 字节。如何解决java编码和swift编码之间的这种差异? 有我的快速代码:

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

            let myKeyData : NSData = ("Fanava@Wrapper!1395" as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData
            let myRawData : NSData = encryptData.data(using: String.Encoding.utf8)! as NSData


   let mykeydatamd5 = Data(bytes: myKeyData.bytes, count: 24) // this key convert to 24 bytes but does not hash to md5 

  let mykeydatamd5 = Data(bytes: myKeyData.md5().bytes, count: 24) // this line converted key to md5(), 24byte, but it 


            let buffer_size : size_t = myRawData.length + kCCBlockSize3DES
            let 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)

            let Crypto_status: CCCryptorStatus =  CCCrypt(operation, algoritm, options, mykeydatamd5.bytes  , keyLength, nil, myRawData.bytes, myRawData.count, buffer, buffer_size, &num_bytes_encrypted)

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

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

                free(buffer)

                return myResult.base64EncodedString(options: [])
            }else{
                free(buffer)

                return nil
            }
        }

【问题讨论】:

  • 这是非常不安全的,有几个原因。 1、新作品不要使用3DES,使用AES。 2.不要使用ECB模式,不安全,见ECB mode,向下滚动到企鹅。而是使用随机 IV 的 CBC 模式,只需在加密数据前加上 IV 以用于解密。 3.不要使用MD5从密码中导出密钥,使用PBKDF2(Password Based Key Derivation Function 2)和rounds值,大约需要100ms。
  • @zaph 感谢您的回复,但我不得不使用tripleDes 和MD5,因为我们发送数据的服务器只接受tripleDes 和MD5,我不能使用其他任何东西。
  • 好的,但遗憾的是服务器实现不安全,用户处于危险之中,这真的是不可接受的。
  • 尝试使用 JavaKey = "Fanava@Wrapper!1" 和 iOSKey = "Fanava@Wrapper!1Fanava@W"
  • 嗨 @ava 刚刚回来查看您的查询是否已解决。

标签: ios swift3 md5 tripledes


【解决方案1】:

这里是可以为 TrippleDES 轻松修改的示例代码:

来自子集的 SO 文档部分

用于 CBC 模式下的 AES 加密,带有随机 IV (Swift 3+)

iv 是加密数据的前缀

aesCBC128Encrypt 将创建一个随机 IV 并作为加密代码的前缀。
aesCBC128Decrypt 将在解密期间使用前缀 IV。

输入是数据,键是数据对象。如果需要在调用方法中转换为和/或从编码形式(如 Base64)。

密钥的长度应为 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。如果使用其他密钥大小,则会引发错误。

PKCS#7 padding是默认设置的。

此示例需要 Common Crypto
项目必须有桥接头:
#import &lt;CommonCrypto/CommonCrypto.h&gt;
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 mode 所需的详细信息中解放出来。

为了安全起见,加密数据也应该具有身份验证功能,此示例代码不提供此功能,以便更小并允许与其他平台更好的互操作性。

还缺少从密码中导出密钥的密钥,建议使用PBKDF2,将文本密码用作密钥材料。

有关强大的生产就绪多平台加密代码,请参阅RNCryptor

如果你必须这个功能可以修改为 3DES。

对于 PBKDF2 加密 **Password Based Key Derivation 2 (Swift 3+)

基于密码的密钥派生既可用于从密码文本派生加密密钥,也可用于保存密码以进行身份​​验证。

此示例代码提供了多种哈希算法,包括 SHA1、SHA256、SHA512。

rounds 参数用于使计算变慢,以便攻击者每次尝试都必须花费大量时间。典型的延迟值在 100 毫秒到 500 毫秒之间,如果性能不可接受,可以使用更短的值。

此示例需要 Common Crypto
项目必须有桥接头:
#import &lt;CommonCrypto/CommonCrypto.h&gt;
Security.framework 添加到项目中。

参数:

password     password String  
salt         salt Data  
keyByteCount number of key bytes to generate
rounds       Iteration rounds

returns      Derived key


func pbkdf2SHA1(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA1), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}

func pbkdf2SHA256(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}

func pbkdf2SHA512(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}

func pbkdf2(hash :CCPBKDFAlgorithm, password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    let passwordData = password.data(using:String.Encoding.utf8)!
    var derivedKeyData = Data(repeating:0, count:keyByteCount)

    let derivationStatus = derivedKeyData.withUnsafeMutableBytes {derivedKeyBytes in
        salt.withUnsafeBytes { saltBytes in

            CCKeyDerivationPBKDF(
                CCPBKDFAlgorithm(kCCPBKDF2),
                password, passwordData.count,
                saltBytes, salt.count,
                hash,
                UInt32(rounds),
                derivedKeyBytes, derivedKeyData.count)
        }
    }
    if (derivationStatus != 0) {
        print("Error: \(derivationStatus)")
        return nil;
    }

    return derivedKeyData
}

示例用法:

let password     = "password"
//let salt       = "saltData".data(using: String.Encoding.utf8)!
let salt         = Data(bytes: [0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
let keyByteCount = 16
let rounds       = 100000

let derivedKey = pbkdf2SHA1(password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
print("derivedKey (SHA1): \(derivedKey! as NSData)")

示例输出:

derivedKey (SHA1): <6b9d4fa3 0385d128 f6d196ee 3f1d6dbf>

【讨论】:

    猜你喜欢
    • 2012-01-01
    • 2017-08-13
    • 2018-08-26
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    相关资源
    最近更新 更多