在Python和Swift之间交换加密消息

发布于 2025-02-11 13:04:01 字数 1045 浏览 2 评论 0原文

我需要有一个Python代码和Swift Code Exchange加密消息。

这是我尝试的方法:

  1. 在回顾

选项之后,我认为一种符号密钥算法可以很好地工作。

在Python(照常)中,它是直接加密和解密

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

:似乎最初是直接的,沿着:

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

但是,我找不到与匹配Python的蕨类植物相匹配的算法。

  1. chacha

在寻找问题时,我登上了这个惊人的来自Bram的答案来自Bram。非常不幸的是,它仅解决了我问题的一侧:在Python中加密消息并将其解码在Swift中。我还需要反向过程。

如何解决这个问题?

I need to have a python code and a swift code exchange encrypted message.

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:

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.

  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. I also need the reverse process.

How to solve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

云柯 2025-02-18 13:04:01

首先,我们首先需要一种创建安全的随机值以生成IV和键的方法。您还可以使用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)
    }
}

然后,我们需要计算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])
}

以及具有SHA-256哈希功能的HMAC。我建议在此处使用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)
}

这将所有这些融合到以下

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)")

示例输出中,

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

我们可以在Python中使用Cryptography.io的实现来使用它。

from cryptography.fernet import Fernet

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

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

To start, we first need a way to create secure random values to generate the IV and keys. You can also generate the keys using CryptoKit's SymmetricKey and extract the data from them, but for now, I'll use this function.

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.

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. I recommend using CryptoKit's HMAC implementation here, but to keep things simple, I went with the CommonCrypto implementation.

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

from cryptography.fernet import Fernet

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

Fernet(key).decrypt(token)
# b'Hello world!'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文