import XCTest import CryptoKit @testable import Closer final class CoupleEncryptionManagerTests: XCTestCase { func testWrapUnwrapRoundTrip() throws { let key = try CoupleEncryptionManager.generateCoupleKey() let phrase = try RecoveryKeyManager.generatePhrase() let wrapped = try CoupleEncryptionManager.wrap(key, with: phrase) XCTAssertEqual(wrapped.kdfParams, CoupleEncryptionManager.kdfParamsTag) XCTAssertEqual(wrapped.kdfSalt.count, CoupleEncryptionManager.saltBytes) // Ciphertext includes nonce (12) + at least 1 byte plaintext + tag (16). XCTAssertGreaterThanOrEqual(wrapped.ciphertext.count, 29) let unwrapped = try CoupleEncryptionManager.unwrap(wrapped, with: phrase) XCTAssertEqual(unwrapped.rawKey.bytes, key.rawKey.bytes) } func testBadPhraseRejects() throws { let key = try CoupleEncryptionManager.generateCoupleKey() let phrase = try RecoveryKeyManager.generatePhrase() let wrapped = try CoupleEncryptionManager.wrap(key, with: phrase) let wrongPhrase = RecoveryKeyManager.normalize(phrase) + " wrong" XCTAssertThrowsError(try CoupleEncryptionManager.unwrap(wrapped, with: wrongPhrase)) } func testInvitePhraseEncryptionRoundTrip() throws { let phrase = try RecoveryKeyManager.generatePhrase() let inviteCode = "ABC123" let blob = try CoupleEncryptionManager.encryptRecoveryPhrase(phrase, with: inviteCode) let recovered = try CoupleEncryptionManager.decryptRecoveryPhrase(blob, with: inviteCode) XCTAssertEqual(recovered, phrase) } func testInvitePhraseBadCodeRejects() throws { let phrase = try RecoveryKeyManager.generatePhrase() let blob = try CoupleEncryptionManager.encryptRecoveryPhrase(phrase, with: "ABC123") XCTAssertThrowsError(try CoupleEncryptionManager.decryptRecoveryPhrase(blob, with: "ABC124")) } }