尝试解密时 CryptoKit authenticationFailure
CryptoKit authenticationFailure when try decrypt
我正在尝试使用 SymmetricKey 解密负载。我试过 ChaChaPoly 和 AES.GCM 打开 sealedBox 但我仍然得到 CryptoKit.CryptoKitError.authenticationFailure
这是我的实现:
let iv: [UInt8] = [0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F]
func generatePair() {
let priv = P256.KeyAgreement.PrivateKey()
privateKey = priv
publicKey = priv.publicKey
}
func createSymmetricKey(serverPublicKeyPEM: String) -> SymmetricKey? {
guard let privateKey = privateKey,
let publicKey = publicKey else { return nil }
do {
let serverPubKey = try P256.KeyAgreement.PublicKey(pemRepresentation: serverPublicKeyPEM)
let shared = try privateKey.sharedSecretFromKeyAgreement(with: serverPubKey)
let symetricKey = shared.hkdfDerivedSymmetricKey(using: SHA256.self,
salt: Data(bytes: iv, count: iv.count),
sharedInfo: publicKey.rawRepresentation + serverPubKey.rawRepresentation,
outputByteCount: 32)
return symetricKey
} catch {
//TODO: Handle Error
print("error \(error)")
return nil
}
}
func decrypt(payload: String, symmetricKey: SymmetricKey) {
guard let cipherText = Data(base64Encoded: payload) else { return }
do {
// let sealedBox = try ChaChaPoly.SealedBox(combined: cipherText)
// let decrypted = try ChaChaPoly.open(sealedBox, using: symmetricKey)
let sb = try AES.GCM.SealedBox(combined: cipherText)
let decrypted = try AES.GCM.open(sb, using: symmetricKey)
print("")
} catch {
print("error: \(error)") //here getting CryptoKit.CryptoKitError.authenticationFailure
}
}
我也知道后端的实现方式:
public static String encrypt(String sessionKey, String devicePublicKey, String plainString) throws Exception {
byte[] plain = Base64.getEncoder().encodeToString(plainString.getBytes(StandardCharsets.UTF_8)).getBytes();
SecretKey key = generateSharedSecret(decodePrivateKey(sessionKey), decodePublicKey( devicePublicKey));
Cipher encryptor = Cipher.getInstance("AES/CTR/NoPadding", BouncyCastleProvider.PROVIDER_NAME);
IvParameterSpec ivSpec = new IvParameterSpec(INITIALIZATION_VECTOR);
encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
return Base64.getEncoder().encodeToString(encryptor.doFinal(plain, 0, plain.length));
}
问题可能在于您使用的初始化向量或随机数。计算字节数,我们得出总共 16 个 nonce 字节,即使 GCM 只需要 12 个。现在,使用 16 并不一定是好是坏,但 CryptoKit 实现在调用 AES.GCM.SealedBox(combined:)
时假定为 12 个字节。为了支持 16 个随机数字节,您将不得不使用 AES.GCM.SealedBox(nonce:ciphertext:tag:)
。
let ciphertext = Data(...)
do {
let nonce = try AES.GCM.Nonce(data: ciphertext[0 ..< 16]
let message = ciphertext[16 ..< ciphertext.count - 16]
let tag = ciphertext[ciphertext.count - 16 ..< ciphertext.count]
let sb = try AES.GCM.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag)
let decrypted = try AES.GCM.open(sb, using: key)
} catch {
print("Error: \(error)")
}
查看您的服务器代码,确保共享机密不是 'just' 共享机密。 generateSharedSecret
听起来像是执行密钥交换后的秘密,但没有执行密钥派生(HKDF,如 Swift 代码中所示)。
还要深入查看您的服务器代码,确保您的响应数据包含随机数、加密消息和标记。一些加密实现迫使您自己进行这种连接。因此,您应该确保 doFinal
包含标签(仅限 GCM)和 return Base64(nonce + encrypted message + tag)
,而不是 return Base64(doFinal)
(伪代码)。同样,该标签仅在使用 GCM 时使用。
正如评论中也提到的,GCM 和 CTR 是 AES 的不同操作模式。确保在双方上使用相同的,因此 iOS 和服务器上的 GCM 或 iOS 和服务器上的 CTR。不这样做,总是会导致解密失败。
如果你想使用 CTR,你必须看看 CommonCrypto
,旧的 Apple 加密库。这个实现了 CTR,但不支持 GCM(因为实现从未发布)。
最后一点,在使用 GCM 时,还要确保您的附加身份验证数据(如果有)是正确的。
我正在尝试使用 SymmetricKey 解密负载。我试过 ChaChaPoly 和 AES.GCM 打开 sealedBox 但我仍然得到 CryptoKit.CryptoKitError.authenticationFailure 这是我的实现:
let iv: [UInt8] = [0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F]
func generatePair() {
let priv = P256.KeyAgreement.PrivateKey()
privateKey = priv
publicKey = priv.publicKey
}
func createSymmetricKey(serverPublicKeyPEM: String) -> SymmetricKey? {
guard let privateKey = privateKey,
let publicKey = publicKey else { return nil }
do {
let serverPubKey = try P256.KeyAgreement.PublicKey(pemRepresentation: serverPublicKeyPEM)
let shared = try privateKey.sharedSecretFromKeyAgreement(with: serverPubKey)
let symetricKey = shared.hkdfDerivedSymmetricKey(using: SHA256.self,
salt: Data(bytes: iv, count: iv.count),
sharedInfo: publicKey.rawRepresentation + serverPubKey.rawRepresentation,
outputByteCount: 32)
return symetricKey
} catch {
//TODO: Handle Error
print("error \(error)")
return nil
}
}
func decrypt(payload: String, symmetricKey: SymmetricKey) {
guard let cipherText = Data(base64Encoded: payload) else { return }
do {
// let sealedBox = try ChaChaPoly.SealedBox(combined: cipherText)
// let decrypted = try ChaChaPoly.open(sealedBox, using: symmetricKey)
let sb = try AES.GCM.SealedBox(combined: cipherText)
let decrypted = try AES.GCM.open(sb, using: symmetricKey)
print("")
} catch {
print("error: \(error)") //here getting CryptoKit.CryptoKitError.authenticationFailure
}
}
我也知道后端的实现方式:
public static String encrypt(String sessionKey, String devicePublicKey, String plainString) throws Exception {
byte[] plain = Base64.getEncoder().encodeToString(plainString.getBytes(StandardCharsets.UTF_8)).getBytes();
SecretKey key = generateSharedSecret(decodePrivateKey(sessionKey), decodePublicKey( devicePublicKey));
Cipher encryptor = Cipher.getInstance("AES/CTR/NoPadding", BouncyCastleProvider.PROVIDER_NAME);
IvParameterSpec ivSpec = new IvParameterSpec(INITIALIZATION_VECTOR);
encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
return Base64.getEncoder().encodeToString(encryptor.doFinal(plain, 0, plain.length));
}
问题可能在于您使用的初始化向量或随机数。计算字节数,我们得出总共 16 个 nonce 字节,即使 GCM 只需要 12 个。现在,使用 16 并不一定是好是坏,但 CryptoKit 实现在调用 AES.GCM.SealedBox(combined:)
时假定为 12 个字节。为了支持 16 个随机数字节,您将不得不使用 AES.GCM.SealedBox(nonce:ciphertext:tag:)
。
let ciphertext = Data(...)
do {
let nonce = try AES.GCM.Nonce(data: ciphertext[0 ..< 16]
let message = ciphertext[16 ..< ciphertext.count - 16]
let tag = ciphertext[ciphertext.count - 16 ..< ciphertext.count]
let sb = try AES.GCM.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag)
let decrypted = try AES.GCM.open(sb, using: key)
} catch {
print("Error: \(error)")
}
查看您的服务器代码,确保共享机密不是 'just' 共享机密。 generateSharedSecret
听起来像是执行密钥交换后的秘密,但没有执行密钥派生(HKDF,如 Swift 代码中所示)。
还要深入查看您的服务器代码,确保您的响应数据包含随机数、加密消息和标记。一些加密实现迫使您自己进行这种连接。因此,您应该确保 doFinal
包含标签(仅限 GCM)和 return Base64(nonce + encrypted message + tag)
,而不是 return Base64(doFinal)
(伪代码)。同样,该标签仅在使用 GCM 时使用。
正如评论中也提到的,GCM 和 CTR 是 AES 的不同操作模式。确保在双方上使用相同的,因此 iOS 和服务器上的 GCM 或 iOS 和服务器上的 CTR。不这样做,总是会导致解密失败。
如果你想使用 CTR,你必须看看 CommonCrypto
,旧的 Apple 加密库。这个实现了 CTR,但不支持 GCM(因为实现从未发布)。
最后一点,在使用 GCM 时,还要确保您的附加身份验证数据(如果有)是正确的。