简体   繁体   English

在 python 和 swift 之间交换加密消息

[英]Exchanging encrypted messages between python and swift

I need to have a python code and a swift code exchange encrypted message.我需要一个 python 代码和一个快速代码交换加密消息。

Here's what I tried:这是我尝试过的:

  1. Fernet费内特

After a review of the options, I thought that a symetric key algorithm could work well.在审查了这些选项之后,我认为对称密钥算法可以很好地工作。

In python (as usual), it is straightforward to encrypt and decrypt :在 python 中(像往常一样),加密和解密很简单

Fernet(key).encrypt(b"mdg") # encrypt
Fernet(key).decrypt(encryptedMsg) # decrypt

In swift, it seemed initially straightforward with something along the lines of:很快,它最初看起来很简单,大致如下:

func encrypt(key: String, msg: String) throws -> String {
  let data = Data(base64URL: key)!
  let symetricKey = try! SymmetricKey(data: d)
  let msgUtf8 = msg.data(using: .utf8)!
  let sealBox = try! AES.GCM.seal(msgUtf8, using: symetricKey, nonce: nil)
  return sealBox.combined.base64EncodedString();
}

However, I have been unable to find the algorithm in swift matching python's Fernet.但是,我一直无法在 swift 匹配 python 的 Fernet 中找到该算法。

  1. ChaCha恰恰

While searching for the problem, I landed on this amazing answer from Bram.在寻找问题时,我从布拉姆那里得到了这个惊人的答案 Very unfortunately it only solves one side of my problem : encrypting messages in python and decoding them in swift.非常不幸的是,它只解决了我的问题的一方面:在 python 中加密消息并快速解码它们。 I also need the reverse process.我也需要相反的过程。

How to solve this?如何解决这个问题?

To start, we first need a way to create secure random values to generate the IV and keys.首先,我们首先需要一种方法来创建安全的随机值来生成 IV 和密钥。 You can also generate the keys using CryptoKit's SymmetricKey and extract the data from them, but for now, I'll use this function.您还可以使用 CryptoKit 的SymmetricKey生成密钥并从中提取数据,但现在,我将使用此函数。

extension Data {
    static func secureRandom(ofSize size: Int) -> Data {
        var output = [UInt8](repeating: 0, count: size)
        _ = SecRandomCopyBytes(kSecRandomDefault, size, &output)
        return Data(output)
    }
}

We then require the possibility to compute the AES CBC ciphertext, which can be done using CommonCrypto.然后,我们需要计算 AES CBC 密文的可能性,这可以使用 CommonCrypto 来完成。

func encrypt(plaintext: Data, key: Data, iv: Data) -> Data {
    var encryptor: CCCryptorRef?
    defer {
        CCCryptorRelease(encryptor)
    }

    var key = Array(key)
    var iv = Array(iv)
    var plaintext = Array(plaintext)

    CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES), CCOperation(kCCOptionPKCS7Padding), &key, key.count, &iv, &encryptor)

    var outputBytes = [UInt8](repeating: 0, count: CCCryptorGetOutputLength(encryptor, plaintext.count, false))
    CCCryptorUpdate(encryptor, &plaintext, plaintext.count, &outputBytes, outputBytes.count, nil)

    var movedBytes = 0
    var finalBytes = [UInt8](repeating: 0, count: CCCryptorGetOutputLength(encryptor, 0, true))
    CCCryptorFinal(encryptor, &finalBytes, finalBytes.count, &movedBytes)

    return Data(outputBytes + finalBytes[0 ..< movedBytes])
}

and the HMAC with the SHA-256 hash function.以及具有 SHA-256 哈希函数的 HMAC。 I recommend using CryptoKit's HMAC implementation here, but to keep things simple, I went with the CommonCrypto implementation.我推荐在这里使用 CryptoKit 的 HMAC 实现,但为了简单起见,我选择了 CommonCrypto 实现。

func computeHMAC(_ data: Data, using key: Data) -> Data {
    var data = Array(data)
    var key = Array(key)
    var macOut = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
    CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), &key, key.count, &data, data.count, &macOut)
    return Data(macOut)
}

This brings all of this together into the following这将所有这些整合到以下内容中

let plaintext = Data("Hello world!".utf8)

let signingKey = Data.secureRandom(ofSize: kCCKeySizeAES128)
let cryptoKey = Data.secureRandom(ofSize: kCCKeySizeAES128)
let fernetKey = (signingKey + cryptoKey).base64EncodedString()

let version: [UInt8] = [0x80]
let timestamp: [UInt8] = {
    let timestamp = Int(Date().timeIntervalSince1970).bigEndian
    return withUnsafeBytes(of: timestamp, Array.init)
}()
let iv = Data.secureRandom(ofSize: kCCBlockSizeAES128)
let ciphertext = encrypt(plaintext: plaintext, key: cryptoKey, iv: iv)
let hmac = computeHMAC(version + timestamp + iv + ciphertext, using: signingKey)

let fernetToken = (version + timestamp + iv + ciphertext + hmac).base64EncodedString()

print("Fernet key: \(fernetKey)")
print("Fernet token: \(fernetToken)")

An example output can be一个示例输出可以是

Fernet key: 7EwFlYNKTGfj+2fSgL3AUqtrRqRs4D1TWNK7t2XbGJQ=
Fernet token: gAAAAABivCLM0y0poDtGOohT1yK4XTDJppYPJdu4fuDTZ5tb9P9KP5ACgX8aJq4imsSdbzOCcvY3Tueo4FYbwyG+ZugozILL+Q==

We can use this in python using cryptography.io's implementation我们可以使用 cryptography.io 的实现在 python 中使用它

from cryptography.fernet import Fernet

key = b'7EwFlYNKTGfj+2fSgL3AUqtrRqRs4D1TWNK7t2XbGJQ='
token = b'gAAAAABivCLM0y0poDtGOohT1yK4XTDJppYPJdu4fuDTZ5tb9P9KP5ACgX8aJq4imsSdbzOCcvY3Tueo4FYbwyG+ZugozILL+Q=='

Fernet(key).decrypt(token)
# b'Hello world!'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM