2016-11-30 57 views
0

我在java代碼中使用tripleDes和MD5算法。還有就是我的Java代碼:在swift中使用TripleDes和MD5

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; 
    } 

我想使用的TripleDES和MD5斯威夫特,我是這個轉換Java代碼迅速,但由於在Java中使用16字節和使用24字節迅速存在迅速的問題。 java和swift編碼之間如何解決這個區別? 有我的SWIFT代碼:

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

      let myKeyData : NSData = ("[email protected]!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 
      } 
     } 
+0

這是有幾個原因非常不安全的。 1. 3DES不應該用於新作品,請使用AES。 2.不要使用ECB模式,這是不安全的,請參閱[ECB模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29),向下滾動到企鵝。 取而代之的是將CBC模式與隨機IV一起使用,只是將加密數據與IV一起用於解密。 3.不要使用MD5從密碼派生密鑰,使用PBKDF2(基於密碼的密鑰派生函數2)的循環值大約需要100ms。 – zaph

+0

@zaph謝謝你的回覆,但我不得不使用tripleDes和MD5,因爲我們發送數據的服務器只接受tripleDes和MD5,而我不能使用其他任何東西。 – ava

+0

好的,但可惜的是服務器的實現並不安全,這是用戶被置於危險之中,而且真的無法接受。 – zaph

回答

0

下面是示例代碼可用於TrippleDES被容易地修改:

從子集SO文檔部分

對於AES加密CBC模式與隨機IV(SWIFT 3+)

的IV被前綴到加密數據

aesCBC128Encrypt將創建一個隨機的IV並以加密的代碼爲前綴。
aesCBC128Decrypt將在解密期間使用前綴IV。

輸入是數據,鍵是數據對象。如果需要的話,如Base64等編碼形式轉換爲和/或在調用方法中。

密鑰的長度應該正好是128位(16字節),192位(24字節)或256位(32字節)。如果使用其他密鑰大小,則會引發錯誤。

PKCS#7 padding默認設置。

這個例子需要公共的密碼
這是需要有一個橋接報的項目:
#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 = "clearData".data(using:String.Encoding.utf8)! 
let keyData = "keyData89".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加密**基於密碼的密鑰派生2(SWIFT 3+)

基於密碼的密鑰派生可用於從密碼文本加密密鑰和保存用於身份驗證密碼,使用這兩種。

有幾種散列算法可以使用,包括本示例代碼提供的SHA1,SHA256,SHA512。

rounds參數用於使計算速度變慢,以便攻擊者必須在每次嘗試中花費大量時間。典型的延遲值在100ms到500ms之間,如果有不可接受的性能,可以使用較短的值。

這個例子需要公共的密碼
這是需要有一個橋接報的項目:
#import <CommonCrypto/CommonCrypto.h>
添加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>