108 lines
3.9 KiB
Swift
108 lines
3.9 KiB
Swift
import XCTest
|
|
import CryptoKit
|
|
@testable import Closer
|
|
|
|
final class KeyboxCryptoTests: XCTestCase {
|
|
private let info = Data("couple-1|q-1|sender-1|recipient-1".utf8)
|
|
|
|
func testWrapUnwrapRoundTrip() throws {
|
|
let recipient = P256.KeyAgreement.PrivateKey()
|
|
let plaintext = Data("secret one-time answer key".utf8)
|
|
|
|
let keybox = try KeyboxCrypto.wrap(
|
|
plaintext: plaintext,
|
|
recipientPublicKey: recipient.publicKey,
|
|
info: info
|
|
)
|
|
XCTAssertEqual(keybox.ephemeralPublicKey.count, 65)
|
|
XCTAssertTrue(keybox.ephemeralPublicKey.first == 0x04)
|
|
XCTAssertEqual(keybox.mac.count, 32)
|
|
|
|
let decoded = try KeyboxCrypto.encode(keybox)
|
|
XCTAssertTrue(decoded.hasPrefix(KeyboxCrypto.keyboxPrefix))
|
|
|
|
let reloaded = try KeyboxCrypto.decode(decoded)
|
|
let recovered = try KeyboxCrypto.unwrap(reloaded, recipientPrivateKey: recipient, info: info)
|
|
XCTAssertEqual(recovered, plaintext)
|
|
}
|
|
|
|
func testAADMismatchRejects() throws {
|
|
let recipient = P256.KeyAgreement.PrivateKey()
|
|
let plaintext = Data("aad-bound secret".utf8)
|
|
let keybox = try KeyboxCrypto.wrap(
|
|
plaintext: plaintext,
|
|
recipientPublicKey: recipient.publicKey,
|
|
info: info
|
|
)
|
|
let wrongInfo = Data("different info".utf8)
|
|
XCTAssertThrowsError(try KeyboxCrypto.unwrap(keybox, recipientPrivateKey: recipient, info: wrongInfo))
|
|
}
|
|
|
|
func testTamperedMACRejects() throws {
|
|
let recipient = P256.KeyAgreement.PrivateKey()
|
|
let plaintext = Data("mac-bound secret".utf8)
|
|
var keybox = try KeyboxCrypto.wrap(
|
|
plaintext: plaintext,
|
|
recipientPublicKey: recipient.publicKey,
|
|
info: info
|
|
)
|
|
var macBytes = Array(keybox.mac)
|
|
macBytes[0] ^= 0x01
|
|
keybox = Keybox(
|
|
ephemeralPublicKey: keybox.ephemeralPublicKey,
|
|
ciphertext: keybox.ciphertext,
|
|
mac: Data(macBytes)
|
|
)
|
|
XCTAssertThrowsError(try KeyboxCrypto.unwrap(keybox, recipientPrivateKey: recipient, info: info))
|
|
}
|
|
|
|
func testTamperedCiphertextRejects() throws {
|
|
let recipient = P256.KeyAgreement.PrivateKey()
|
|
let plaintext = Data("ct-bound secret".utf8)
|
|
var keybox = try KeyboxCrypto.wrap(
|
|
plaintext: plaintext,
|
|
recipientPublicKey: recipient.publicKey,
|
|
info: info
|
|
)
|
|
var ctBytes = Array(keybox.ciphertext)
|
|
ctBytes[12 + 3] ^= 0x01
|
|
keybox = Keybox(
|
|
ephemeralPublicKey: keybox.ephemeralPublicKey,
|
|
ciphertext: Data(ctBytes),
|
|
mac: keybox.mac
|
|
)
|
|
XCTAssertThrowsError(try KeyboxCrypto.unwrap(keybox, recipientPrivateKey: recipient, info: info))
|
|
}
|
|
|
|
func testInfoStringMismatchRejects() throws {
|
|
let recipient = P256.KeyAgreement.PrivateKey()
|
|
let plaintext = Data("info-bound secret".utf8)
|
|
let keybox = try KeyboxCrypto.wrap(
|
|
plaintext: plaintext,
|
|
recipientPublicKey: recipient.publicKey,
|
|
info: Data("a|b|c|d".utf8)
|
|
)
|
|
XCTAssertThrowsError(
|
|
try KeyboxCrypto.unwrap(
|
|
keybox,
|
|
recipientPrivateKey: recipient,
|
|
info: Data("a|b|c|e".utf8)
|
|
)
|
|
)
|
|
}
|
|
|
|
func testEncodeDecodePreservesFields() throws {
|
|
let recipient = P256.KeyAgreement.PrivateKey()
|
|
let keybox = try KeyboxCrypto.wrap(
|
|
plaintext: Data("encode decode".utf8),
|
|
recipientPublicKey: recipient.publicKey,
|
|
info: info
|
|
)
|
|
let encoded = try KeyboxCrypto.encode(keybox)
|
|
let decoded = try KeyboxCrypto.decode(encoded)
|
|
XCTAssertEqual(decoded.ephemeralPublicKey, keybox.ephemeralPublicKey)
|
|
XCTAssertEqual(decoded.ciphertext, keybox.ciphertext)
|
|
XCTAssertEqual(decoded.mac, keybox.mac)
|
|
}
|
|
}
|