Skip to content

Commit 7d1731e

Browse files
committed
Moved masterkey export method from Cryptor to Masterkey (where it belongs), made scryptCostParam parametrizable for speedy test
1 parent ef89254 commit 7d1731e

File tree

4 files changed

+58
-54
lines changed

4 files changed

+58
-54
lines changed

CryptoLib/Cryptor.swift

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@ struct FileHeader {
5454
}
5555

5656
public class Cryptor {
57-
static let defaultScryptSaltSize = 8
58-
static let defaultScryptCostParam = 1 << 15 // 2^15
59-
static let defaultScryptBlockSize = 8
60-
6157
static let fileHeaderLegacyPayloadSize = 8
6258
static let fileHeaderSize = kCCBlockSizeAES128 + fileHeaderLegacyPayloadSize + kCCKeySizeAES256 + Int(CC_SHA256_DIGEST_LENGTH)
6359
static let cleartextChunkSize = 32 * 1024
@@ -75,33 +71,6 @@ public class Cryptor {
7571
self.init(masterkey: masterkey, cryptoSupport: CryptoSupport())
7672
}
7773

78-
// MARK: - Masterkey Encoding
79-
80-
public func encodeMasterkeyJson(password: String, pepper: [UInt8] = [UInt8]()) throws -> Data {
81-
let pw = [UInt8](password.precomposedStringWithCanonicalMapping.utf8)
82-
let salt = try cryptoSupport.createRandomBytes(size: Cryptor.defaultScryptSaltSize)
83-
let saltAndPepper = salt + pepper
84-
let kek = try Scrypt(password: pw, salt: saltAndPepper, dkLen: kCCKeySizeAES256, N: Cryptor.defaultScryptCostParam, r: Cryptor.defaultScryptBlockSize, p: 1).calculate()
85-
86-
let wrappedMasterKey = try Masterkey.wrapMasterKey(rawKey: masterkey.aesMasterKey, kek: kek)
87-
let wrappedHmacKey = try Masterkey.wrapMasterKey(rawKey: masterkey.macMasterKey, kek: kek)
88-
89-
var versionMac = [UInt8](repeating: 0x00, count: Int(CC_SHA256_DIGEST_LENGTH))
90-
let versionBytes = withUnsafeBytes(of: UInt32(masterkey.version).bigEndian, Array.init)
91-
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), masterkey.macMasterKey, masterkey.macMasterKey.count, versionBytes, versionBytes.count, &versionMac)
92-
93-
let masterkeyJson = MasterkeyJson(
94-
scryptSalt: Data(salt).base64EncodedString(),
95-
scryptCostParam: Cryptor.defaultScryptCostParam,
96-
scryptBlockSize: Cryptor.defaultScryptBlockSize,
97-
primaryMasterKey: Data(wrappedMasterKey).base64EncodedString(),
98-
hmacMasterKey: Data(wrappedHmacKey).base64EncodedString(),
99-
versionMac: Data(versionMac).base64EncodedString(),
100-
version: masterkey.version
101-
)
102-
return try JSONEncoder().encode(masterkeyJson)
103-
}
104-
10574
// MARK: - Path Encryption and Decryption
10675

10776
public func encryptDirId(_ dirId: Data) throws -> String {

CryptoLib/Masterkey.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ enum MasterkeyError: Error, Equatable {
2828
}
2929

3030
public class Masterkey {
31+
static let defaultScryptSaltSize = 8
32+
static let defaultScryptCostParam = 1 << 15 // 2^15
33+
static let defaultScryptBlockSize = 8
34+
3135
private(set) var aesMasterKey: [UInt8]
3236
private(set) var macMasterKey: [UInt8]
3337
public let version: Int
@@ -47,7 +51,7 @@ public class Masterkey {
4751
}
4852
}
4953

50-
// MARK: - Masterkey Factory Methods
54+
// MARK: - Factory
5155

5256
public static func createNew() throws -> Masterkey {
5357
let cryptoSupport = CryptoSupport()
@@ -134,4 +138,35 @@ public class Masterkey {
134138
throw MasterkeyError.unwrapFailed(status)
135139
}
136140
}
141+
142+
// MARK: - Export
143+
144+
public func exportEncrypted(password: String, pepper: [UInt8] = [UInt8]()) throws -> Data {
145+
let masterkeyJson: MasterkeyJson = try exportEncrypted(password: password, pepper: pepper)
146+
return try JSONEncoder().encode(masterkeyJson)
147+
}
148+
149+
func exportEncrypted(password: String, pepper: [UInt8], scryptCostParam: Int = Masterkey.defaultScryptCostParam, cryptoSupport: CryptoSupport = CryptoSupport()) throws -> MasterkeyJson {
150+
let pw = [UInt8](password.precomposedStringWithCanonicalMapping.utf8)
151+
let salt = try cryptoSupport.createRandomBytes(size: Masterkey.defaultScryptSaltSize)
152+
let saltAndPepper = salt + pepper
153+
let kek = try Scrypt(password: pw, salt: saltAndPepper, dkLen: kCCKeySizeAES256, N: scryptCostParam, r: Masterkey.defaultScryptBlockSize, p: 1).calculate()
154+
155+
let wrappedMasterKey = try Masterkey.wrapMasterKey(rawKey: aesMasterKey, kek: kek)
156+
let wrappedHmacKey = try Masterkey.wrapMasterKey(rawKey: macMasterKey, kek: kek)
157+
158+
var versionMac = [UInt8](repeating: 0x00, count: Int(CC_SHA256_DIGEST_LENGTH))
159+
let versionBytes = withUnsafeBytes(of: UInt32(version).bigEndian, Array.init)
160+
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), macMasterKey, macMasterKey.count, versionBytes, versionBytes.count, &versionMac)
161+
162+
return MasterkeyJson(
163+
scryptSalt: Data(salt).base64EncodedString(),
164+
scryptCostParam: scryptCostParam,
165+
scryptBlockSize: Masterkey.defaultScryptBlockSize,
166+
primaryMasterKey: Data(wrappedMasterKey).base64EncodedString(),
167+
hmacMasterKey: Data(wrappedHmacKey).base64EncodedString(),
168+
versionMac: Data(versionMac).base64EncodedString(),
169+
version: version
170+
)
171+
}
137172
}

CryptoLibTests/CryptorTests.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,6 @@ class CryptorTests: XCTestCase {
2828
try FileManager.default.removeItem(at: tmpDirURL)
2929
}
3030

31-
func testEncodeMasterkeyJson() throws {
32-
let jsonData = try cryptor.encodeMasterkeyJson(password: "asd")
33-
let decoded = try JSONDecoder().decode(MasterkeyJson.self, from: jsonData)
34-
XCTAssertEqual("8PDw8PDw8PA=", decoded.scryptSalt)
35-
XCTAssertEqual(32768, decoded.scryptCostParam)
36-
XCTAssertEqual(8, decoded.scryptBlockSize)
37-
XCTAssertEqual("nDcSwW65LXWVnry/lAC88aVtZrkB6dUWC9QuLsrRq/ZFCAJaldMtoQ==", decoded.primaryMasterKey)
38-
XCTAssertEqual("HCuwIhdRnXeA3U4Ohm9/m96IML9kH/OuhyR1ygEJ+zJWRnhzOrtz9A==", decoded.hmacMasterKey)
39-
XCTAssertEqual("sAWFgFNhmtMPeNWr4zh+9Ps7GOtT0pknX11PRQ7eC9Q=", decoded.versionMac)
40-
XCTAssertEqual(7, decoded.version)
41-
}
42-
4331
func testEncryptDirId() throws {
4432
let rootDir = try cryptor.encryptDirId("".data(using: .utf8)!)
4533
XCTAssertEqual("VLWEHT553J5DR7OZLRJAYDIWFCXZABOD", rootDir)

CryptoLibTests/MasterkeyTests.swift

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@ class MasterkeyTests: XCTestCase {
1818
// Put teardown code here. This method is called after the invocation of each test method in the class.
1919
}
2020

21-
func testWrapAndUnwrapKey() throws {
22-
let rawKey = [UInt8](repeating: 0x77, count: 32)
23-
let kek = [UInt8](repeating: 0x55, count: 32)
24-
let wrapped = try Masterkey.wrapMasterKey(rawKey: rawKey, kek: kek)
25-
XCTAssertNotNil(wrapped)
26-
let unwrapped = try Masterkey.unwrapMasterKey(wrappedKey: wrapped, kek: kek)
27-
XCTAssertNotNil(unwrapped)
28-
XCTAssertEqual(rawKey, unwrapped)
29-
}
30-
3121
func testCreateFromMasterkeyFile() throws {
3222
let expectedKeys = [UInt8](repeating: 0x00, count: 32)
3323
let jsonData = """
@@ -139,4 +129,26 @@ class MasterkeyTests: XCTestCase {
139129
XCTAssertEqual(error as! MasterkeyError, MasterkeyError.malformedMasterkeyFile("invalid base64 data in versionMac"))
140130
}
141131
}
132+
133+
func testWrapAndUnwrapKey() throws {
134+
let rawKey = [UInt8](repeating: 0x77, count: 32)
135+
let kek = [UInt8](repeating: 0x55, count: 32)
136+
let wrapped = try Masterkey.wrapMasterKey(rawKey: rawKey, kek: kek)
137+
XCTAssertNotNil(wrapped)
138+
let unwrapped = try Masterkey.unwrapMasterKey(wrappedKey: wrapped, kek: kek)
139+
XCTAssertNotNil(unwrapped)
140+
XCTAssertEqual(rawKey, unwrapped)
141+
}
142+
143+
func testExportEncrypted() throws {
144+
let masterkey = Masterkey.createFromRaw(aesMasterKey: [UInt8](repeating: 0x55, count: 32), macMasterKey: [UInt8](repeating: 0x77, count: 32), version: 7)
145+
let json = try masterkey.exportEncrypted(password: "asd", pepper: [UInt8](), scryptCostParam: 2, cryptoSupport: CryptoSupportMock())
146+
XCTAssertEqual("8PDw8PDw8PA=", json.scryptSalt)
147+
XCTAssertEqual(2, json.scryptCostParam)
148+
XCTAssertEqual(8, json.scryptBlockSize)
149+
XCTAssertEqual("jvdghkTc01VISrFly37pgaT/UKtXrDCvZcU3tT9Y98zyzn/pJ91bxw==", json.primaryMasterKey)
150+
XCTAssertEqual("99I+J4bT3rVpZE8yZwKRV9gHVRmQ8XQEujAL9IuwLTc2D3mg5JEjKA==", json.hmacMasterKey)
151+
XCTAssertEqual("sAWFgFNhmtMPeNWr4zh+9Ps7GOtT0pknX11PRQ7eC9Q=", json.versionMac)
152+
XCTAssertEqual(7, json.version)
153+
}
142154
}

0 commit comments

Comments
 (0)