swift - 使用 Apples CryptoKit 在 iOS 和 Kotlin/Java 之间进行跨平台 AES 加密
问题描述
我想使用 Apples CryptoKit 将加密数据从运行 kotlin 应用程序的服务器发送到 iOS 应用程序。我在初始化AES.GCM.SealedBox
和解密数据时遇到问题。一般来说,我不明白 Sealboxstag
的用途。
所以首先是 Kotlin 方面:
fun ByteArray.aesEncrypt(key: ByteArray, iv: ByteArray? = null): ByteArray {
return aes(this, Cipher.ENCRYPT_MODE, key, iv)
}
private fun aes(self: ByteArray, mode: Int, key: ByteArray, iv: ByteArray?): ByteArray{
val skey = SecretKeySpec(key, "AES")
val cipher = Cipher.getInstance("AES/GCM/PKCS5Padding")
println("MODE: ${cipher.algorithm}")
iv?.let {
cipher.init(mode, skey, GCMParameterSpec(128, iv))
}?: run{
cipher.init(mode, skey)
}
val cipherText = ByteArray(cipher.getOutputSize(self.size))
var ctLength = cipher.update(self, 0, self.size, cipherText, 0)
ctLength += cipher.doFinal(cipherText, ctLength)
return cipherText
}
IOS:
static private let privateKey = SymmetricKey(size: SymmetricKeySize.bits128)
static private let nonce = AES.GCM.Nonce()
static func decrypt(_ data: Data) -> Data {
print("Encrypted data \(data.bytes)")
print("Private key: \(privateKey.data.bytes)")
print("Nonce: \(Array(nonce))")
let boxToDecrypt = try! AES.GCM.SealedBox(combined: data)
let plainData = try! AES.GCM.open(boxToDecrypt, using: privateKey)
return plainData
}
当然,双方都有相同的密钥和 iv/nonce。我遇到的错误消息是:
CryptoKit.CryptoKitError.incorrectParameterSize
排队:
let boxToDecrypt = try! AES.GCM.SealedBox(combined: data)
编辑 I:附加有效载荷信息:
服务器(科特林):
Not encrypted: 0,0,0,0,0,0,0,1
Key: 169,152,60,154,77,50,10,63,60,166,48,129,1,68,219,250
IV: 134,191,34,26,111,146,17,54,31,212,74,14
Encrypted: 158,154,213,95,227,42,155,199,169,183,166,67,139,154,198,172,229,82,34,30,40,188,41,73
客户端(iOS):
Encrypted data [158, 154, 213, 95, 227, 42, 155, 199, 169, 183, 166, 67, 139, 154, 198, 172, 229, 82, 34, 30, 40, 188, 41, 73]
Nonce: [134, 191, 34, 26, 111, 146, 17, 54, 31, 212, 74, 14]
Private key: [169, 152, 60, 154, 77, 50, 10, 63, 60, 166, 48, 129, 1, 68, 219, 250]
解决方案
你能用你的设置试试这个(或类似的东西)吗?据我所知,您需要在数据前加上随机数,因为来自 kotlin/java 的数据包含密文和末尾的标签。CryptoKit 需要 nonce || 密文 || 标签。
func decrypt(data: Data) -> String {
// need to prefix data with nonce, because data from kotlin/java contains the cipher text plus the tag at the end.
// we want nonce || ciphertext || tag for CryptoKit to be happy
let combine = nonce + data
if let myNewSealedBox = try? AES.GCM.SealedBox(combined: combine),
let res = try? AES.GCM.open(myNewSealedBox, using: mykey),
let myText = try? String(decoding: res, as: UTF8.self) {
return myText
}
return ""
}
推荐阅读
- python - 有没有办法计算多个数组的所有可能组合?
- javascript - 如何使用 * 屏蔽 keyup 上的前五位数字
- c++ - 带有 `Return` 的 GMock 的`WillOnce` 不会因返回值错误而失败
- java - 如何解决 javax.mail.internet.AddressException: Illegal address in string ``''
- javascript - 数据表在导出到 excel 时重新排列元素
- javascript - 使用 map() 读取 Json 对象
- c# - 如何将两个不同标签的编号结合到一个新标签上?
- reactjs - 如何将数组中的4个元素(对象)添加到本地存储,反应
- python - 我想知道为什么函数总是选择第一个以及如何修复它-Python
- php - 如何获取选定的下拉列表项的值并将其发布到控制器?