快速解密 AES CCM 消息

问题描述 投票:0回答:1

我正在尝试用 Swift 解密一条从我通过蓝牙连接的设备发送的消息。

我正在尝试快速实施本文:

https://www.makinolo.com/blog/2023/10/08/connecting-to-zwift-play-controllers/

我通过以下步骤创建了对称密钥:

let privateKey = P256.KeyAgreement.PrivateKey()
var message = "RideOn".data(using: .utf8)!
message.append(Data([0x01, 0x09]))
let publicKey = privateKey.publicKey
message.append(publicKey.rawRepresentation)
/// sent to peripheral

我收到他们的公钥并创建共享秘密

        let rideOn = "RideOn".data(using: .utf8)!

        guard value.starts(with: rideOn) else {
            logger.error("no ride on?")
            return
        }

        let key = value.dropFirst(8)

        guard let publicKey = try? P256.KeyAgreement.PublicKey(rawRepresentation: key) else {
            logger.debug("wrong key?")
            return
        }

        let salt = key + privateKey.publicKey.rawRepresentation

        guard let sharedSecret = try? privateKey.sharedSecretFromKeyAgreement(with: publicKey) else {
            logger.debug("no shared secret")
            return
        }
        let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(using: SHA256.self, salt: salt, sharedInfo: Data(), outputByteCount: 36)

我开始接收消息,但无法解码消息。这些步骤似乎不适用于 iOS,可能是因为随机数不同?

For decryption you need to extract the 3 parts of the message and call the AES-CCM decrypt function with:

- The AES mode, which is aes-256-ccm
- The IV (initialization Vector) also called nonce (number used once) which is an 8 byte array whose 4 first bytes are the 4 last bytes of the HKDF symmetric key, followed by the 4 bytes of the counter you have received in the message.
The IV / nonce length, which is 8 bytes
- The received MIC, so the algorithm can compare his own calculated MIC with the one provided and authenticate the message
- The received message (only the remaining bytes in the message after stripping the counter and the MIC)

我尝试过以下方法:

使用加密货币:

        let nonceData = symmetricKey.withUnsafeBytes { Data(Array($0)) }[...3] + value[...3]
        let tag = value.suffix(4)
        var value = value
        value = value.dropFirst(4)
        value.removeLast(4)

        do {
            let aes = try AES(key: symmetricKey.withUnsafeBytes { Array($0) }, blockMode: CCM(iv: [UInt8](nonceData), tagLength: 4, messageLength: value.count), padding: .zeroPadding)
            let result = try aes.decrypt([UInt8](value))

            print("Result: \(result)")
        } catch {
            logger.debug("Error: \(error.localizedDescription)")
        }

使用 CryptoKit

        do {
            let nonce = try AES.GCM.Nonce(data: nonceData)

            let sealedBox = try AES.GCM.SealedBox(nonce: nonce, ciphertext: value, tag: tag)
            let result = try AES.GCM.open(sealedBox, using: symmetricKey)

        } catch {
            logger.debug("\(error.localizedDescription)")
        }

我认为创建Nonce有问题,但没有真正的线索,不太熟悉加密/解密。

这是我收到的几条消息:

Own private key: [36, 147, 90, 234, 66, 250, 58, 153, 187, 163, 237, 184, 100, 91, 99, 35, 139, 69, 181, 239, 250, 214, 164, 116, 118, 58, 95, 218, 28, 25, 111, 105]
Own public key: [34, 76, 142, 17, 129, 101, 252, 53, 92, 200, 144, 34, 20, 43, 115, 100, 181, 27, 19, 176, 145, 253, 34, 241, 74, 107, 125, 254, 130, 146, 169, 65, 118, 6, 199, 146, 89, 20, 47, 233, 101, 134, 76, 192, 61, 167, 135, 89, 100, 140, 56, 63, 3, 117, 57, 52, 136, 220, 38, 44, 119, 8, 110, 201]
Click key: [247, 134, 157, 189, 154, 129, 53, 47, 254, 165, 164, 49, 150, 55, 151, 75, 7, 182, 85, 194, 28, 198, 177, 153, 128, 75, 32, 50, 155, 204, 225, 201, 215, 241, 81, 246, 9, 222, 89, 81, 11, 190, 74, 214, 117, 41, 155, 227, 87, 41, 120, 34, 141, 227, 83, 85, 22, 246, 115, 0, 65, 174, 194, 48]
Salt: [247, 134, 157, 189, 154, 129, 53, 47, 254, 165, 164, 49, 150, 55, 151, 75, 7, 182, 85, 194, 28, 198, 177, 153, 128, 75, 32, 50, 155, 204, 225, 201, 215, 241, 81, 246, 9, 222, 89, 81, 11, 190, 74, 214, 117, 41, 155, 227, 87, 41, 120, 34, 141, 227, 83, 85, 22, 246, 115, 0, 65, 174, 194, 48]

After pressing click, a couple of the messages:
[21, 0, 0, 0, 248, 68, 228, 177, 135, 249, 158, 236, 165]
[22, 0, 0, 0, 78, 244, 116, 18, 109, 111, 238, 175, 86]
[23, 0, 0, 0, 122, 90, 33, 237, 14, 237, 234]
[24, 0, 0, 0, 139, 66, 8, 195, 217, 18, 234]
[25, 0, 0, 0, 3, 247, 14, 46, 58, 88, 71]

swift encryption aes cryptoswift apple-cryptokit
1个回答
0
投票

请检查代码中的以下几点:

  • 尽管盐似乎在代码中正确确定了

    let salt = key + privateKey.publicKey.rawRepresentation
    

    在您的示例数据中,它似乎仅包含设备端的公钥。

  • 随机数似乎确定不正确。根据说明,随机数由 HKDF 密钥的最后 4 个字节和消息的前 4 个字节组成,即它应该类似于:

    let nonceData = symmetricKey.withUnsafeBytes { Data(Array($0)) }.suffix(4) + valueMsg.prefix(4)
    
  • 此外,AES 密钥似乎确定不正确。 AES 密钥由 36 字节 HKDF 密钥的前 32 字节(对应于 AES-256)组成,即它应该类似于:

    let aesKey = symmetricKey.withUnsafeBytes { Data(Array($0)) }.prefix(32)
    
  • 在使用CryptoSwift进行AES/CCM解密时,标签似乎没有被考虑在内。正确的方法是将密文和标签的串联

    valueCtTag
    传递给
    decrypt()
    ,其中
    valueCtTag
    类似于:

    let valueCtTag = valueMsg.dropFirst(4)
    

    messageLength
    指定:
    valueCtTag.count - 4
    ,如
    tagLength
    适用:
    4

  • 关于填充:不应该是

    .zeroPadding
    ,而是
    .noPadding

通过这些更改,解密对我有用(正如成功的身份验证所证明的那样)。

但是,我只使用发布的 Swift 代码验证了共享密钥和 HKDF 密钥(如上所述进行了修改),而不是 CCM 解密本身(因为我目前没有可用的 CryptoSwift 环境)。
我已经使用(修改后的)Swift 代码中确定的参数在 Python 中成功执行了 AES/CCM 解密,这证明密文“原则上”可以使用 AES/CCM 通过这些参数成功解密。因此,如果 CryptoSwift 的 CCM 实现没有错误,那么使用 CryptoSwift 对给定密文的解密也应该成功。 关于您的 CryptoKit 解密:这不起作用,因为 GCM 和 CCM 是不同的操作模式,不兼容。

这里是使用(修改后的)Swift 代码生成的中间值(除了最后一个值
decrypted

,它是如上所述用 Python 确定的)。这至少应该让您更容易缩小可能的错误范围(所有值都是十六进制编码):

other public key, hex: f7869dbd9a81352ffea5a4319637974b07b655c21cc6b199804b20329bcce1c9d7f151f609de59510bbe4ad675299be3572978228de3535516f6730041aec230
private key, hex:      24935aea42fa3a99bba3edb8645b63238b45b5effad6a474763a5fda1c196f69
public key, hex:       224c8e118165fc355cc89022142b7364b51b13b091fd22f14a6b7dfe8292a9417606c79259142fe965864cc03da78759648c383f0375393488dc262c77086ec9
salt, hex:             f7869dbd9a81352ffea5a4319637974b07b655c21cc6b199804b20329bcce1c9d7f151f609de59510bbe4ad675299be3572978228de3535516f6730041aec230224c8e118165fc355cc89022142b7364b51b13b091fd22f14a6b7dfe8292a9417606c79259142fe965864cc03da78759648c383f0375393488dc262c77086ec9
shared secret, hex:    a9137e57dd92892464a807b19fa353d5dd39a1b5a1153ae36fb7a86ee75248e5
HKDF key, hex:         211a0ef8a89e5c60962b9c9dd9b7492328c0115a0db840e710b9cace78668cdf8cb25c08

第一条消息:
[21, 0, 0, 0, 248, 68, 228, 177, 135, 249, 158, 236, 165]

message, hex:          15000000f844e4b187f99eeca5
counter, hex:          15000000
ciphertext, hex:       f844e4b187
tag, hex:              f99eeca5
ciphertext|tag, hex:   f844e4b187f99eeca5
nonce, hex:            8cb25c0815000000
AES key, hex:          211a0ef8a89e5c60962b9c9dd9b7492328c0115a0db840e710b9cace78668cdf
decrypted, hex:        3708011001 

© www.soinside.com 2019 - 2024. All rights reserved.