2017-09-28 360 views
1

我是在Swift中使用密碼加密字符串的字符串,但不知道如何去做。我需要像這樣的東西Swift - 使用用戶密碼加密和解密字符串

let password = "password" 
let message = "messageToEncrypt" 
let encryptedMessage = encrypt(message, password) 
... 

let decryptedMessage = decrypt(encryptedMessage, password) 

任何意見將不勝感激。

由於

UPDATE < - 刪除這個部分現在

UPDATE 2

確定我現在有以下:

func testEnc() throws { 

    let ivKey = "tEi1H3E1aj26XNro" 
    let message = "Test Message" 
    let password = "pass123" 

    let aesKey = password.padding(toLength: 32, withPad: "0", startingAt: 0) 

    do { 
     let messageArray = Array(message.utf8) 
     let encrypted = try AES(key: aesKey, iv: ivKey, blockMode: .CBC, padding: .pkcs7).encrypt(messageArray) 
     let encryptedString = String.init(bytes: encrypted, encoding: .utf8) 
     let decrypted = try AES(key: aesKey, iv: ivKey, blockMode: .CBC, padding: .pkcs7).decrypt(encrypted) 
     let decryptedString = String.init(bytes: decrypted, encoding: .utf8) 
     assert(message == decryptedString) 
    } catch { 
     print(error) 
    } 
} 

在上面的代碼,該消息被正確加密並解密ñ。

decryptedString返回與message相同的值,這是完美的。不過,我需要存儲加密值。在上面的代碼中,encryptedString總是返回nil。 AES加密Array<UInt8>沒有作爲字節字符串類嗎?

+0

潛在相關閱讀:https://stackoverflow.com/questions/27072021/aes-encrypt-and-decrypt – CollinD

+0

我已經閱讀過這篇文章,但是這是基於使用密鑰和iv的基於密鑰的加密。我需要一個基於密碼的方法。如果這是要走的路。我如何生成一個密鑰,只給出一個密碼? –

+0

https://security.stackexchange.com/questions/38828/how-can-i-securely-convert-a-string-password-to-a-key-used-in-aes – CollinD

回答

3

請參閱下面更新的部分刪除部分。我已經離開了刪除線出部分給上下文的意見,並展示如何不爲安全起見,做

我一直在使用CryptoSwift

func testEnc() throws { 

    //has to be 16 characters 
    //ivKey is only hardcoded for use of this example 
    let ivKey = "tEi1H3E1aj26XNro" 
    let message = "Test Message" 
    let password = "pass123" 

    //key has to be 32 characters so we pad the password 
    let aesKey = password.padding(toLength: 32, withPad: "0", startingAt: 0) 

    let encrypted = try message.encryptToBase64(cipher: AES(key: aesKey, iv: ivKey, blockMode: .CBC, padding: .pkcs7)) 
    //returns: beQ7u8hBGdFYqNP5z4gBGg== 

    let decrypted = try encrypted?.decryptBase64ToString(cipher: AES(key: aesKey, iv: ivKey, blockMode: .CBC, padding: .pkcs7)) 
    //returns: Test Message 
    assert(message == decrypted) 

} 

UPDATE的工作了

上述方法儘管起作用,但是不安全; 請閱讀這個答案評論基於評價和反饋更多信息

,我已經寫了一個使用該框架RNCryptor

要密型和解密消息我用下面的2種方法一個新的例子。

func encryptMessage(message: String, encryptionKey: String) throws -> String { 
     let messageData = message.data(using: .utf8)! 
     let cipherData = RNCryptor.encrypt(data: messageData, withPassword: encryptionKey) 
     return cipherData.base64EncodedString() 
    } 

    func decryptMessage(encryptedMessage: String, encryptionKey: String) throws -> String { 

     let encryptedData = Data.init(base64Encoded: encryptedMessage)! 
     let decryptedData = try RNCryptor.decrypt(data: encryptedData, withPassword: encryptionKey) 
     let decryptedString = String(data: decryptedData, encoding: .utf8)! 

     return decryptedString 
    } 

在我的使用情況下,我需要能夠加密和解密基於關閉,可以改變一個密碼來處理,而不必重新加密的一切。

我所做的是生成隨機32字符串並加密與密碼。如果用戶更改密碼,他們只需用舊密碼解密密鑰,並用新密碼重新加密。這確保了所有現有內容都可以在用戶密碼保護下解密。

要生成加密密鑰是使用下面的方法:

func generateEncryptionKey(withPassword password:String) throws -> String { 
    let randomData = RNCryptor.randomData(ofLength: 32) 
    let cipherData = RNCryptor.encrypt(data: randomData, withPassword: password) 
    return cipherData.base64EncodedString() 
} 

注意:您將只爲用戶生成此加密密鑰一次,因爲它會然後存儲在某個地方,用戶可以使用其返回自己的密碼。

+0

請注意,這是令人難以置信的不安全。你拋棄了絕大多數的AES密鑰空間。人類可分類的密碼與密鑰不同。您必須使用KDF(通常爲CryptoSwift中提供的PBKDF2)將密碼延伸到密鑰中。這將需要生成一個隨機鹽,您將需要與加密數據一起存儲。這也是非常不安全的,因爲你有一個固定的IV。 IVs不能像這樣硬編碼。您需要生成一個隨機數據並將其與加密數據一起傳遞。 –

+0

Rob,你能舉一個例子說明如何使用用戶密碼加密並使用相同密碼解密的字符串?你提出了一些有效的觀點,但沒有任何實例可以讓我看到正確的做事方式,但很難做出調整。 我的代碼的用例將加密一個私鑰,以便它可以存儲在數據庫中。私鑰將與公鑰配對以處理主加密。私鑰需要使用用戶的密碼進行加密,並使用用戶的密碼和其他人的密碼進行解密。 –

+0

爲了增加,IV不會像上面那樣被硬編碼。我將使用諸如用戶密碼的md5之類的東西或其他單向加密。 –

0

其中最受歡迎的圖書館之一是CryptoSwift(超過4000顆星!)。它提供了許多您可能感興趣的加密相關功能。

對於你的問題,我假設你想要做基於AES的加密,並且該消息很小(但進一步下來,有一個更大的文件等例子)。使用上面提到的庫,代碼(從庫的網頁本身所佔 - 請向下滾動):

do { 
    let aes = try AES(key: "passwordpassword", iv: "drowssapdrowssap") 
    let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8)) 
} catch { } 

其中一個問的問題是如何獲得IV(初始化向量)。在這個例子中,IV僅僅是密碼的反轉,在現實世界的應用中這可能不是一個好主意。原則是IV不需要保密。它只需要是隨機的,如果可能的話,是唯一的。所以,你可以用文件將IV保存在帶有密文的數據庫中。

+0

我正在嘗試這個,但我得到以下錯誤 '塊大小和初始化向量必須是相同的長度!' 我通過反轉密碼生成我的IV –

+0

「,這在實際應用中可能不是一個好主意。」這是一個非常糟糕的主意,除非密碼的長度恰好是一個塊,否則不起作用。密碼也不是同一件事情的關鍵。將人爲密碼作爲AES密鑰傳遞是非常不安全的(它破壞了AES密鑰大小的大部分好處)。雖然CryptoSwift是一個很好的軟件包,但它是一個非常低級的軟件包。它假定你有很強的背景以正確使用加密原語,並且會高興地讓你構建高度不安全的事物。 –

+0

我不知道你爲什麼得到這個錯誤。我只是試過這個,它似乎在工作。你可以發佈你的代碼嗎? (對不起... newbee在這裏stackoverflow,所以不知道所有的鐘聲和口哨聲)。 @RobNapier我完全同意。但我試圖儘可能簡單,而不是暗示你應該這樣做。 基於 密鑰加密是艱難的 - 醃製,創建一個(獨一無二)加密隨機IV等也同樣重要。我完全同意你的看法。 – mgeek