Skip to content

Commit

Permalink
add compatibility test for IOS
Browse files Browse the repository at this point in the history
tutadb#1937
  • Loading branch information
tutao-mac committed Jan 9, 2025
1 parent 8d0447d commit 4dc57d3
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 107 deletions.
151 changes: 78 additions & 73 deletions app-ios/TutanotaSharedFramework/Crypto/IosNativeCryptoFacade.swift
Original file line number Diff line number Diff line change
@@ -1,84 +1,89 @@
import TutanotaSharedFramework
import CryptoKit
import tutasdk

/// High-level cryptographic operations API
/// Is an actor because we want to have serial execution for all the cryptogaphic operations, doing them in parallel is usually too
/// much for the device.
public actor IosNativeCryptoFacade: NativeCryptoFacade {
public init() {}

public func aesEncryptFile(_ key: DataWrapper, _ fileUri: String, _ iv: DataWrapper) async throws -> EncryptedFileInfo {

if !FileUtils.fileExists(atPath: fileUri) { throw CryptoError(message: "File to encrypt does not exist \(fileUri)") }
let encryptedFolder = try FileUtils.getEncryptedFolder()
let fileName = (fileUri as NSString).lastPathComponent
let encryptedFilePath = (encryptedFolder as NSString).appendingPathComponent(fileName)
let plainTextData = try Data(contentsOf: URL(fileURLWithPath: fileUri))
let outputData = try aesEncryptData(plainTextData, withKey: key.data, withIV: iv.data)
let result = EncryptedFileInfo(uri: encryptedFilePath, unencryptedSize: plainTextData.count)

try outputData.write(to: URL(fileURLWithPath: encryptedFilePath))

return result
}

public func aesDecryptFile(_ key: DataWrapper, _ fileUri: String) async throws -> String {
if !FileUtils.fileExists(atPath: fileUri) { throw CryptoError(message: "File to decrypt does not exist") }

let encryptedData = try Data(contentsOf: URL(fileURLWithPath: fileUri))
let plaintextData = try aesDecryptData(encryptedData, withKey: key.data)

let decryptedFolder = try FileUtils.getDecryptedFolder()
let fileName = (fileUri as NSString).lastPathComponent
let plaintextPath = (decryptedFolder as NSString).appendingPathComponent(fileName)
try plaintextData.write(to: URL(fileURLWithPath: plaintextPath), options: .atomic)

return plaintextPath
}

public func rsaEncrypt(_ publicKey: RsaPublicKey, _ data: DataWrapper, _ seed: DataWrapper) async throws -> DataWrapper {
try tutasdk.rsaEncryptWithPublicKeyComponents(
data: data.data,
seed: seed.data,
modulus: publicKey.modulus,
publicExponent: UInt32(publicKey.publicExponent)
)
.wrap()
}

public func rsaDecrypt(_ privateKey: RsaPrivateKey, _ data: DataWrapper) async throws -> DataWrapper {
try tutasdk.rsaDecryptWithPrivateKeyComponents(
ciphertext: data.data,
modulus: privateKey.modulus,
privateExponent: privateKey.privateExponent,
primeP: privateKey.primeP,
primeQ: privateKey.primeQ
)
.wrap()
}

public func argon2idGeneratePassphraseKey(_ passphrase: String, _ salt: DataWrapper) async throws -> DataWrapper {
try tutasdk.argon2idGenerateKeyFromPassphrase(passphrase: passphrase, salt: salt.data).wrap()
}

public func generateKyberKeypair(_ seed: DataWrapper) async throws -> TutanotaSharedFramework.KyberKeyPair {
let keypair = tutasdk.generateKyberKeypair()
return KyberKeyPair(publicKey: KyberPublicKey(raw: keypair.publicKey.wrap()), privateKey: KyberPrivateKey(raw: keypair.privateKey.wrap()))
}

public func kyberEncapsulate(_ publicKey: KyberPublicKey, _ seed: DataWrapper) async throws -> TutanotaSharedFramework.KyberEncapsulation {
do {
let sdkEncapsulation = try tutasdk.kyberEncapsulateWithPubKey(publicKeyBytes: publicKey.raw.data)
return KyberEncapsulation(ciphertext: sdkEncapsulation.ciphertext.wrap(), sharedSecret: sdkEncapsulation.sharedSecret.wrap())
} catch { throw CryptoError(message: error.localizedDescription) }
}

public func kyberDecapsulate(_ privateKey: KyberPrivateKey, _ ciphertext: DataWrapper) async throws -> DataWrapper {
do { return try tutasdk.kyberDecapsulateWithPrivKey(privateKeyBytes: privateKey.raw.data, ciphertext: ciphertext.data).wrap() } catch {
throw CryptoError(message: error.localizedDescription)
}

public init() {}

public func aesEncryptFile(_ key: DataWrapper, _ fileUri: String, _ iv: DataWrapper) async throws -> EncryptedFileInfo {

if !FileUtils.fileExists(atPath: fileUri) { throw CryptoError(message: "File to encrypt does not exist \(fileUri)") }
let encryptedFolder = try FileUtils.getEncryptedFolder()
let fileName = (fileUri as NSString).lastPathComponent
let encryptedFilePath = (encryptedFolder as NSString).appendingPathComponent(fileName)
let plainTextData = try Data(contentsOf: URL(fileURLWithPath: fileUri))
let outputData = try aesEncryptData(plainTextData, withKey: key.data, withIV: iv.data)
let result = EncryptedFileInfo(uri: encryptedFilePath, unencryptedSize: plainTextData.count)

try outputData.write(to: URL(fileURLWithPath: encryptedFilePath))

return result
}

public func aesDecryptFile(_ key: DataWrapper, _ fileUri: String) async throws -> String {
if !FileUtils.fileExists(atPath: fileUri) { throw CryptoError(message: "File to decrypt does not exist") }

let encryptedData = try Data(contentsOf: URL(fileURLWithPath: fileUri))
let plaintextData = try aesDecryptData(encryptedData, withKey: key.data)

let decryptedFolder = try FileUtils.getDecryptedFolder()
let fileName = (fileUri as NSString).lastPathComponent
let plaintextPath = (decryptedFolder as NSString).appendingPathComponent(fileName)
try plaintextData.write(to: URL(fileURLWithPath: plaintextPath), options: .atomic)

return plaintextPath
}

public func rsaEncrypt(_ publicKey: RsaPublicKey, _ data: DataWrapper, _ seed: DataWrapper) async throws -> DataWrapper {
try tutasdk.rsaEncryptWithPublicKeyComponents(
data: data.data,
seed: seed.data,
modulus: publicKey.modulus,
publicExponent: UInt32(publicKey.publicExponent)
)
.wrap()
}

public func rsaDecrypt(_ privateKey: RsaPrivateKey, _ data: DataWrapper) async throws -> DataWrapper {
try tutasdk.rsaDecryptWithPrivateKeyComponents(
ciphertext: data.data,
modulus: privateKey.modulus,
privateExponent: privateKey.privateExponent,
primeP: privateKey.primeP,
primeQ: privateKey.primeQ
)
.wrap()
}

public func argon2idGeneratePassphraseKey(_ passphrase: String, _ salt: DataWrapper) async throws -> DataWrapper {
try tutasdk.argon2idGenerateKeyFromPassphrase(passphrase: passphrase, salt: salt.data).wrap()
}

public func generateKyberKeypair(_ seed: DataWrapper) async throws -> TutanotaSharedFramework.KyberKeyPair {
let keypair = tutasdk.generateKyberKeypair()
return KyberKeyPair(publicKey: KyberPublicKey(raw: keypair.publicKey.wrap()), privateKey: KyberPrivateKey(raw: keypair.privateKey.wrap()))
}

public func kyberEncapsulate(_ publicKey: KyberPublicKey, _ seed: DataWrapper) async throws -> TutanotaSharedFramework.KyberEncapsulation {
do {
let sdkEncapsulation = try tutasdk.kyberEncapsulateWithPubKey(publicKeyBytes: publicKey.raw.data)
return KyberEncapsulation(ciphertext: sdkEncapsulation.ciphertext.wrap(), sharedSecret: sdkEncapsulation.sharedSecret.wrap())
} catch { throw CryptoError(message: error.localizedDescription) }
}

public func kyberDecapsulate(_ privateKey: KyberPrivateKey, _ ciphertext: DataWrapper) async throws -> DataWrapper {
do { return try tutasdk.kyberDecapsulateWithPrivKey(privateKeyBytes: privateKey.raw.data, ciphertext: ciphertext.data).wrap() } catch {
throw CryptoError(message: error.localizedDescription)
}

}

public func hmacSha256(_ key: Data, _ data: Data) async throws -> HashedAuthenticationCode<SHA256> {
return HMAC<SHA256>.authenticationCode(for: data, using: SymmetricKey(data: key))
}
}

private func CryptoError(message: String) -> Error { TUTErrorFactory.createError(withDomain: TUT_CRYPTO_ERROR, message: message) }
14 changes: 14 additions & 0 deletions app-ios/tutanotaTests/CompatibilityTestSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ class CompatibilityTestSwift: XCTestCase {
}
}

func testHmacSha256() async throws {
let tests = (testData!["hmacSha256Tests"] as? [[String: Any]])!
for test in tests {
let keyHex = TUTEncodingConverter.hex(toBytes: test["keyHex"]! as! String)
let dataHex = TUTEncodingConverter.hex(toBytes: test["dataHex"]! as! String)
let hmacSha256TagHex = TUTEncodingConverter.hex(toBytes: test["hmacSha256TagHex"]! as! String)
let facade = IosNativeCryptoFacade()
let tag = try await facade.hmacSha256(keyHex, dataHex)
var output: [UInt8] = []
output.append(contentsOf: tag)
XCTAssertEqual(Data(output), hmacSha256TagHex)
}
}

private func hexComponents(fromHex hex: String, sizeDivisor: Int) throws -> [Data] {
let converted = TUTEncodingConverter.hex(toBytes: hex)
var offset = 0
Expand Down
76 changes: 42 additions & 34 deletions libs/electron-updater.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11584,46 +11584,54 @@ const coerce$1 = (version, options) => {
};
var coerce_1 = coerce$1;

class LRUCache {
constructor () {
this.max = 1000;
this.map = new Map();
}
var lrucache;
var hasRequiredLrucache;

function requireLrucache () {
if (hasRequiredLrucache) return lrucache;
hasRequiredLrucache = 1;
class LRUCache {
constructor () {
this.max = 1000;
this.map = new Map();
}

get (key) {
const value = this.map.get(key);
if (value === undefined) {
return undefined
} else {
// Remove the key from the map and add it to the end
this.map.delete(key);
this.map.set(key, value);
return value
}
}
get (key) {
const value = this.map.get(key);
if (value === undefined) {
return undefined
} else {
// Remove the key from the map and add it to the end
this.map.delete(key);
this.map.set(key, value);
return value
}
}

delete (key) {
return this.map.delete(key)
}
delete (key) {
return this.map.delete(key)
}

set (key, value) {
const deleted = this.delete(key);
set (key, value) {
const deleted = this.delete(key);

if (!deleted && value !== undefined) {
// If cache is full, delete the least recently used item
if (this.map.size >= this.max) {
const firstKey = this.map.keys().next().value;
this.delete(firstKey);
}
if (!deleted && value !== undefined) {
// If cache is full, delete the least recently used item
if (this.map.size >= this.max) {
const firstKey = this.map.keys().next().value;
this.delete(firstKey);
}

this.map.set(key, value);
}
this.map.set(key, value);
}

return this
}
}
return this
}
}

var lrucache = LRUCache;
lrucache = LRUCache;
return lrucache;
}

var range;
var hasRequiredRange;
Expand Down Expand Up @@ -11845,7 +11853,7 @@ function requireRange () {

range = Range;

const LRU = lrucache;
const LRU = requireLrucache();
const cache = new LRU();

const parseOptions = parseOptions_1;
Expand Down

0 comments on commit 4dc57d3

Please sign in to comment.