-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from soramitsu/feature/keystore-encoding
Add keystore encoding
- Loading branch information
Showing
15 changed files
with
409 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import Foundation | ||
|
||
enum RandomDataError: Error { | ||
case generatorFailed | ||
} | ||
|
||
extension Data { | ||
static func gerateRandomBytes(of length: Int) throws -> Data { | ||
var data = Data(count: length) | ||
let result = data.withUnsafeMutableBytes { | ||
SecRandomCopyBytes(kSecRandomDefault, length, $0.baseAddress!) | ||
} | ||
|
||
guard result == errSecSuccess else { | ||
throw RandomDataError.generatorFailed | ||
} | ||
|
||
return data | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import Foundation | ||
import IrohaCrypto | ||
import TweetNacl | ||
|
||
public class KeystoreBuilder { | ||
private var name: String? | ||
private var creationDate = Date() | ||
private var genesisHash: String? | ||
|
||
public init() {} | ||
} | ||
|
||
extension KeystoreBuilder: KeystoreBuilding { | ||
public func with(name: String) -> Self { | ||
self.name = name | ||
return self | ||
} | ||
|
||
public func with(creationDate: Date) -> Self { | ||
self.creationDate = creationDate | ||
return self | ||
} | ||
|
||
public func with(genesisHash: String) -> Self { | ||
self.genesisHash = genesisHash | ||
return self | ||
} | ||
|
||
public func build(from data: KeystoreData, password: String?) throws -> KeystoreDefinition { | ||
let scryptParameters = try ScryptParameters() | ||
|
||
let scryptData: Data | ||
|
||
if let password = password { | ||
guard let passwordData = password.data(using: .utf8) else { | ||
throw KeystoreExtractorError.invalidPasswordFormat | ||
} | ||
|
||
scryptData = passwordData | ||
} else { | ||
scryptData = Data() | ||
} | ||
|
||
let encryptionKey = try IRScryptKeyDeriviation() | ||
.deriveKey(from: scryptData, | ||
salt: scryptParameters.salt, | ||
scryptN: UInt(scryptParameters.scryptN), | ||
scryptP: UInt(scryptParameters.scryptP), | ||
scryptR: UInt(scryptParameters.scryptR), | ||
length: UInt(KeystoreConstants.encryptionKeyLength)) | ||
|
||
let nonce = try Data.gerateRandomBytes(of: KeystoreConstants.nonceLength) | ||
|
||
let secretKeyData: Data | ||
switch data.cryptoType { | ||
case .sr25519: | ||
secretKeyData = try SNPrivateKey(rawData: data.secretKeyData).toEd25519Data() | ||
case .ed25519: | ||
secretKeyData = data.secretKeyData | ||
case .ecdsa: | ||
secretKeyData = data.secretKeyData | ||
} | ||
|
||
let pcksData = KeystoreConstants.pkcs8Header + secretKeyData + | ||
KeystoreConstants.pkcs8Divider + data.publicKeyData | ||
let encrypted = try NaclSecretBox.secretBox(message: pcksData, nonce: nonce, key: encryptionKey) | ||
let encoded = scryptParameters.encode() + nonce + encrypted | ||
|
||
let encodingType = [KeystoreEncodingType.scrypt.rawValue, KeystoreEncodingType.xsalsa.rawValue] | ||
let encodingContent = [KeystoreEncodingContent.pkcs8.rawValue, data.cryptoType.rawValue] | ||
let keystoreEncoding = KeystoreEncoding(content: encodingContent, | ||
type: encodingType, | ||
version: String(KeystoreConstants.version)) | ||
|
||
let meta = KeystoreMeta(name: name, | ||
createdAt: Int64(creationDate.timeIntervalSince1970), | ||
genesisHash: genesisHash) | ||
|
||
return KeystoreDefinition(address: data.address, | ||
encoded: encoded.base64EncodedString(), | ||
encoding: keystoreEncoding, | ||
meta: meta) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import Foundation | ||
|
||
public protocol KeystoreExtracting { | ||
func extractFromDefinition(_ info: KeystoreDefinition, | ||
password: String?) throws -> KeystoreData | ||
} | ||
|
||
public protocol KeystoreBuilding { | ||
func with(name: String) -> Self | ||
func with(creationDate: Date) -> Self | ||
func with(genesisHash: String) -> Self | ||
|
||
func build(from data: KeystoreData, password: String?) throws -> KeystoreDefinition | ||
} | ||
|
||
public enum KeystoreExtractorError: Error { | ||
case invalidBase64 | ||
case missingScryptSalt | ||
case missingScryptN | ||
case missingScryptP | ||
case missingScryptR | ||
case unsupportedEncoding | ||
case unsupportedContent | ||
case unsupportedCryptoType | ||
case invalidPasswordFormat | ||
case missingPkcs8Header | ||
case missingPkcs8Divider | ||
} | ||
|
||
public enum KeystoreBuilderError: Error { | ||
case invalidPasswordFormat | ||
} | ||
|
||
enum KeystoreEncodingType: String { | ||
case scrypt = "scrypt" | ||
case xsalsa = "xsalsa20-poly1305" | ||
} | ||
|
||
enum KeystoreEncodingContent: String { | ||
case pkcs8 = "pkcs8" | ||
} | ||
|
||
public struct KeystoreConstants { | ||
public static let nonceLength = 24 | ||
public static let encryptionKeyLength = 32 | ||
public static let pkcs8Header = Data(bytes: [48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32]) | ||
public static let pkcs8Divider = Data(bytes: [161, 35, 3, 33, 0]) | ||
public static let version = 3 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.