Remove CryptoSwift add CryptoKit. Bump OS Versions
This commit is contained in:
parent
8e61453f48
commit
133e80df35
|
@ -1 +0,0 @@
|
|||
github "krzyzanowskim/CryptoSwift" "0.14.0"
|
|
@ -13,12 +13,11 @@
|
|||
s.author = { "Keefer Taylor" => "keefer@keefertaylor.com" }
|
||||
s.source = { :git => "https://github.com/keefertaylor/MnemonicKit.git", :tag => "1.3.10" }
|
||||
s.source_files = "MnemonicKit/**/*.swift",
|
||||
s.swift_version = "4.2"
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.osx.deployment_target = "10.10"
|
||||
|
||||
s.dependency "CryptoSwift", "~> 0.14.0"
|
||||
s.swift_version = "5.1"
|
||||
s.ios.deployment_target = "13.0"
|
||||
s.osx.deployment_target = "10.15"
|
||||
|
||||
s.framework = "CryptoKit"
|
||||
s.test_spec "Tests" do |test_spec|
|
||||
test_spec.source_files = "Tests/*.swift"
|
||||
test_spec.resources = ["Tests/*.json"]
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0DDAF3A42408728600EA9427 /* PKC5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDAF3A32408728600EA9427 /* PKC5.swift */; };
|
||||
0DDAF3A52408728600EA9427 /* PKC5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDAF3A32408728600EA9427 /* PKC5.swift */; };
|
||||
122777029525BA9CC4F9A958 /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B9024EB02AB18E1F44789A /* Mnemonic.swift */; };
|
||||
2A51344C2F30A6CE1A391BCF /* MnemonicKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5EC633D7524CD344B44513 /* MnemonicKitTests.swift */; };
|
||||
2C9FBE1A25B2CA86DB509726 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA1EBAC8ABDF9E72ABA1B642 /* CryptoSwift.framework */; };
|
||||
422A84796316566997821D77 /* vectors.json in Resources */ = {isa = PBXBuildFile; fileRef = C3E5287598681E0527694214 /* vectors.json */; };
|
||||
59FE4CF322226154B9B687CE /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8871A4FF644B8E4F13723E6 /* CryptoSwift.framework */; };
|
||||
5A11F552AAEA9E58CE8CC50D /* CryptoSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F8871A4FF644B8E4F13723E6 /* CryptoSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
81D18E658D26212E4D7647D8 /* String+MnemonicData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 256E6CB62D82160ACBA1512E /* String+MnemonicData.swift */; };
|
||||
8DC3D3DA23DBEAD93257DE4F /* MnemonicKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC7EE929BD11BA8AB38F9C19 /* MnemonicKit.framework */; };
|
||||
|
@ -78,6 +78,7 @@
|
|||
/* Begin PBXFileReference section */
|
||||
0A5E025936BA30D49D80AF51 /* Chinese.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Chinese.swift; sourceTree = "<group>"; };
|
||||
0A5EC633D7524CD344B44513 /* MnemonicKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicKitTests.swift; sourceTree = "<group>"; };
|
||||
0DDAF3A32408728600EA9427 /* PKC5.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKC5.swift; sourceTree = "<group>"; };
|
||||
12B9024EB02AB18E1F44789A /* Mnemonic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = "<group>"; };
|
||||
1645FE576891F45DC72864F6 /* MnemonicKitTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = MnemonicKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1D6F81AB601CF04F3F1E52E3 /* English.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = English.swift; sourceTree = "<group>"; };
|
||||
|
@ -86,7 +87,7 @@
|
|||
65B1627123A1131289B4110A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
7DCB97C4881969FDB72C61DB /* MnemonicKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MnemonicKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BA1EBAC8ABDF9E72ABA1B642 /* CryptoSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CryptoSwift.framework; sourceTree = "<group>"; };
|
||||
C3E5287598681E0527694214 /* vectors.json */ = {isa = PBXFileReference; path = vectors.json; sourceTree = "<group>"; };
|
||||
C3E5287598681E0527694214 /* vectors.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = vectors.json; sourceTree = "<group>"; };
|
||||
D2D9394FFD7755F40E53D60E /* Data+BitArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+BitArray.swift"; sourceTree = "<group>"; };
|
||||
DC7EE929BD11BA8AB38F9C19 /* MnemonicKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MnemonicKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EBA32888ED203FE1DA16BFF1 /* MnemonicKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MnemonicKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -114,7 +115,6 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
59FE4CF322226154B9B687CE /* CryptoSwift.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -122,7 +122,6 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2C9FBE1A25B2CA86DB509726 /* CryptoSwift.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -162,6 +161,7 @@
|
|||
12B9024EB02AB18E1F44789A /* Mnemonic.swift */,
|
||||
256E6CB62D82160ACBA1512E /* String+MnemonicData.swift */,
|
||||
07836B522CFA5AB2F61C4F9F /* Language */,
|
||||
0DDAF3A32408728600EA9427 /* PKC5.swift */,
|
||||
);
|
||||
path = MnemonicKit;
|
||||
sourceTree = "<group>";
|
||||
|
@ -354,7 +354,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "swiftlint autocorrect --config .swiftlint.yml";
|
||||
shellScript = "swiftlint autocorrect --config .swiftlint.yml\n";
|
||||
};
|
||||
E8B531151B3FAE302CDA4BEF /* SwiftLint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
@ -385,6 +385,7 @@
|
|||
EFBEB3B343A9FDDD7B67FF88 /* Data+BitArray.swift in Sources */,
|
||||
D4460C3982D7B9A90D99C790 /* English.swift in Sources */,
|
||||
C3A836752BC9FC7C89A398C5 /* Mnemonic.swift in Sources */,
|
||||
0DDAF3A52408728600EA9427 /* PKC5.swift in Sources */,
|
||||
9374718ABBF77ACE41A92B18 /* String+MnemonicData.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -397,6 +398,7 @@
|
|||
8EAFFDA8F2A30674EA9EBBBC /* Data+BitArray.swift in Sources */,
|
||||
934F1409AF864AAA0AB52FDA /* English.swift in Sources */,
|
||||
122777029525BA9CC4F9A958 /* Mnemonic.swift in Sources */,
|
||||
0DDAF3A42408728600EA9427 /* PKC5.swift in Sources */,
|
||||
81D18E658D26212E4D7647D8 /* String+MnemonicData.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -448,7 +450,7 @@
|
|||
);
|
||||
INFOPLIST_FILE = MnemonicKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -482,6 +484,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.keefertaylor.MnemonicKit-macOS";
|
||||
PRODUCT_NAME = MnemonicKit;
|
||||
SDKROOT = macosx;
|
||||
|
@ -510,6 +513,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.keefertaylor.MnemonicKit-macOS";
|
||||
PRODUCT_NAME = MnemonicKit;
|
||||
SDKROOT = macosx;
|
||||
|
@ -575,7 +579,7 @@
|
|||
);
|
||||
INFOPLIST_FILE = MnemonicKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -653,7 +657,12 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(PROJECT_DIR)/Carthage/Build/iOS";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
||||
);
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -710,7 +719,12 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(PROJECT_DIR)/Carthage/Build/iOS";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,6 +1,4 @@
|
|||
// Copyright Keefer Taylor, 2018
|
||||
|
||||
import CryptoSwift
|
||||
import Foundation
|
||||
|
||||
public extension UInt8 {
|
||||
|
@ -24,9 +22,18 @@ public extension UInt8 {
|
|||
public extension Data {
|
||||
func toBitArray() -> [String] {
|
||||
var toReturn = [String]()
|
||||
for num: UInt8 in bytes {
|
||||
for num in [UInt8](self) {
|
||||
toReturn.append(contentsOf: num.mnemonicBits())
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
}
|
||||
public extension Array where Element == UInt8 {
|
||||
func toBitArray() -> [String] {
|
||||
var toReturn = [String]()
|
||||
for num in self {
|
||||
toReturn.append(contentsOf: num.mnemonicBits())
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,143 +1,164 @@
|
|||
// Copyright Keefer Taylor, 2018
|
||||
|
||||
import CryptoSwift
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
import Security
|
||||
|
||||
public enum MnemonicLanguageType {
|
||||
case english
|
||||
case chinese
|
||||
case english
|
||||
case chinese
|
||||
|
||||
func words() -> [String] {
|
||||
switch self {
|
||||
case .english:
|
||||
return String.englishMnemonics
|
||||
case .chinese:
|
||||
return String.chineseMnemonics
|
||||
func words() -> [String] {
|
||||
switch self {
|
||||
case .english:
|
||||
return String.englishMnemonics
|
||||
case .chinese:
|
||||
return String.chineseMnemonics
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Mnemonic {
|
||||
/// Generate a mnemonic from the given hex string in the given language.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - hexString: The hex string to generate a mnemonic from.
|
||||
/// - language: The language to use. Default is english.
|
||||
public static func mnemonicString(from hexString: String, language: MnemonicLanguageType = .english) -> String? {
|
||||
let seedData = hexString.mnemonicData()
|
||||
let hashData = seedData.sha256()
|
||||
let checkSum = hashData.toBitArray()
|
||||
var seedBits = seedData.toBitArray()
|
||||
/// Generate a mnemonic from the given hex string in the given language.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - hexString: The hex string to generate a mnemonic from.
|
||||
/// - language: The language to use. Default is english.
|
||||
public static func mnemonicString(from hexString: String, language: MnemonicLanguageType = .english) -> String? {
|
||||
let seedData = hexString.mnemonicData()
|
||||
let hashData = SHA256.hash(data: seedData)
|
||||
let checkSum = hashData.bytes.toBitArray()
|
||||
var seedBits = seedData.toBitArray()
|
||||
|
||||
for i in 0 ..< seedBits.count / 32 {
|
||||
seedBits.append(checkSum[i])
|
||||
}
|
||||
|
||||
let words = language.words()
|
||||
|
||||
let mnemonicCount = seedBits.count / 11
|
||||
var mnemonic = [String]()
|
||||
for i in 0 ..< mnemonicCount {
|
||||
let length = 11
|
||||
let startIndex = i * length
|
||||
let subArray = seedBits[startIndex ..< startIndex + length]
|
||||
let subString = subArray.joined(separator: "")
|
||||
|
||||
let index = Int(strtoul(subString, nil, 2))
|
||||
mnemonic.append(words[index])
|
||||
}
|
||||
return mnemonic.joined(separator: " ")
|
||||
}
|
||||
|
||||
/// Generate a deterministic seed string from the given inputs.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - mnemonic: The mnemonic to use.
|
||||
/// - iterations: The iterations to perform in the PBKDF2 algorithm. Default is 2048.
|
||||
/// - passphrase: An optional passphrase. Default is the empty string.
|
||||
/// - language: The language to use. Default is english.
|
||||
public static func deterministicSeedString(
|
||||
from mnemonic: String,
|
||||
iterations: Int = 2_048,
|
||||
passphrase: String = "",
|
||||
language _: MnemonicLanguageType = .english
|
||||
) -> String? {
|
||||
guard self.validate(mnemonic: mnemonic),
|
||||
let normalizedData = self.normalized(string: mnemonic),
|
||||
let saltData = normalized(string: "mnemonic" + passphrase) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let passwordBytes = normalizedData.bytes
|
||||
let saltBytes = saltData.bytes
|
||||
do {
|
||||
let bytes =
|
||||
try PKCS5.PBKDF2(password: passwordBytes, salt: saltBytes, iterations: iterations, variant: .sha512).calculate()
|
||||
return bytes.toHexString()
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a mnemonic of the given strength and given language.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - strength: The strength to use. This must be a multiple of 32.
|
||||
/// - language: The language to use. Default is english.
|
||||
public static func generateMnemonic(strength: Int, language: MnemonicLanguageType = .english)
|
||||
-> String? {
|
||||
guard strength % 32 == 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let count = strength / 8
|
||||
let bytes = [UInt8](repeating: 0, count: count)
|
||||
guard SecRandomCopyBytes(kSecRandomDefault, count, UnsafeMutablePointer<UInt8>(mutating: bytes)) != -1 else {
|
||||
return nil
|
||||
}
|
||||
let data = Data(bytes)
|
||||
let hexString = data.toHexString()
|
||||
|
||||
return mnemonicString(from: hexString, language: language)
|
||||
}
|
||||
|
||||
/// Validate that the given string is a valid mnemonic.
|
||||
public static func validate(mnemonic: String) -> Bool {
|
||||
let normalizedMnemonic = mnemonic.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let mnemonicComponents = normalizedMnemonic.components(separatedBy: " ")
|
||||
guard !mnemonicComponents.isEmpty else {
|
||||
return false
|
||||
}
|
||||
|
||||
// Use the first component of the mnemonic to determine the language, then make sure all
|
||||
// subsequent components are in that language.
|
||||
if String.englishMnemonics.contains(mnemonicComponents[0]) {
|
||||
for mnemonicComponent in mnemonicComponents {
|
||||
guard String.englishMnemonics.contains(mnemonicComponent) else {
|
||||
return false
|
||||
for i in 0 ..< seedBits.count / 32 {
|
||||
seedBits.append(checkSum[i])
|
||||
}
|
||||
}
|
||||
return true
|
||||
} else if String.chineseMnemonics.contains(mnemonicComponents[0]) {
|
||||
for mnemonicComponent in mnemonicComponents {
|
||||
guard String.chineseMnemonics.contains(mnemonicComponent) else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/// Change a string into data.
|
||||
private static func normalized(string: String) -> Data? {
|
||||
guard let data = string.data(using: .utf8, allowLossyConversion: true),
|
||||
let dataString = String(data: data, encoding: .utf8),
|
||||
let normalizedData = dataString.data(using: .utf8, allowLossyConversion: false) else {
|
||||
return nil
|
||||
let words = language.words()
|
||||
|
||||
let mnemonicCount = seedBits.count / 11
|
||||
var mnemonic = [String]()
|
||||
for i in 0 ..< mnemonicCount {
|
||||
let length = 11
|
||||
let startIndex = i * length
|
||||
let subArray = seedBits[startIndex ..< startIndex + length]
|
||||
let subString = subArray.joined(separator: "")
|
||||
|
||||
let index = Int(strtoul(subString, nil, 2))
|
||||
mnemonic.append(words[index])
|
||||
}
|
||||
return mnemonic.joined(separator: " ")
|
||||
}
|
||||
|
||||
/// Generate a deterministic seed string from the given inputs.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - mnemonic: The mnemonic to use.
|
||||
/// - iterations: The iterations to perform in the PBKDF2 algorithm. Default is 2048.
|
||||
/// - passphrase: An optional passphrase. Default is the empty string.
|
||||
/// - language: The language to use. Default is english.
|
||||
public static func deterministicSeedString(
|
||||
from mnemonic: String,
|
||||
iterations: Int = 2_048,
|
||||
passphrase: String = "",
|
||||
language _: MnemonicLanguageType = .english
|
||||
) -> String? {
|
||||
guard self.validate(mnemonic: mnemonic),
|
||||
let normalizedData = self.normalized(string: mnemonic),
|
||||
let saltData = normalized(string: "mnemonic" + passphrase) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let passwordBytes = normalizedData.map { Int8(bitPattern: $0) }
|
||||
|
||||
do {
|
||||
let bytes =
|
||||
try PKCS5.PBKDF2SHA512(password: passwordBytes, salt: [UInt8](saltData), iterations: iterations)
|
||||
return bytes.hexString
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a mnemonic of the given strength and given language.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - strength: The strength to use. This must be a multiple of 32.
|
||||
/// - language: The language to use. Default is english.
|
||||
public static func generateMnemonic(strength: Int, language: MnemonicLanguageType = .english)
|
||||
-> String? {
|
||||
guard strength % 32 == 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let count = strength / 8
|
||||
var bytes = [UInt8](repeating: 0, count: count)
|
||||
|
||||
guard SecRandomCopyBytes(kSecRandomDefault, count, &bytes) == errSecSuccess else { return nil }
|
||||
|
||||
return mnemonicString(from: bytes.hexString, language: language)
|
||||
}
|
||||
|
||||
/// Validate that the given string is a valid mnemonic.
|
||||
public static func validate(mnemonic: String) -> Bool {
|
||||
let normalizedMnemonic = mnemonic.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let mnemonicComponents = normalizedMnemonic.components(separatedBy: " ")
|
||||
guard !mnemonicComponents.isEmpty else {
|
||||
return false
|
||||
}
|
||||
|
||||
// Use the first component of the mnemonic to determine the language, then make sure all
|
||||
// subsequent components are in that language.
|
||||
if String.englishMnemonics.contains(mnemonicComponents[0]) {
|
||||
for mnemonicComponent in mnemonicComponents {
|
||||
guard String.englishMnemonics.contains(mnemonicComponent) else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
} else if String.chineseMnemonics.contains(mnemonicComponents[0]) {
|
||||
for mnemonicComponent in mnemonicComponents {
|
||||
guard String.chineseMnemonics.contains(mnemonicComponent) else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/// Change a string into data.
|
||||
fileprivate static func normalized(string: String) -> Data? {
|
||||
guard let data = string.data(using: .utf8, allowLossyConversion: true),
|
||||
let dataString = String(data: data, encoding: .utf8),
|
||||
let normalizedData = dataString.data(using: .utf8, allowLossyConversion: false) else {
|
||||
return nil
|
||||
}
|
||||
return normalizedData
|
||||
}
|
||||
}
|
||||
|
||||
extension PKCS5 {
|
||||
public static func PBKDF2SHA512(password: String, salt: String, iterations: Int = 2_048, keyLength: Int = 64) throws -> Array<UInt8> {
|
||||
|
||||
guard let saltData = Mnemonic.normalized(string: salt) else {
|
||||
throw PKCS5.Error.invalidInput
|
||||
}
|
||||
|
||||
return try PBKDF2SHA512(password: password.utf8.map({ Int8(bitPattern: $0) }), salt: [UInt8](saltData), iterations: iterations, keyLength: keyLength)
|
||||
}
|
||||
}
|
||||
|
||||
extension Digest {
|
||||
var bytes: [UInt8] { Array(makeIterator()) }
|
||||
var data: Data { Data(bytes) }
|
||||
var hexString: String {
|
||||
bytes.hexString
|
||||
}
|
||||
}
|
||||
|
||||
extension Array where Element == UInt8 {
|
||||
var hexString: String {
|
||||
self.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
return normalizedData
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// PKCS5.swift
|
||||
//
|
||||
//
|
||||
// Created by Liu Pengpeng on 2019/10/10.
|
||||
//
|
||||
import CommonCrypto
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
|
||||
public struct PKCS5 {
|
||||
public enum Error: Swift.Error {
|
||||
case invalidInput
|
||||
}
|
||||
|
||||
public static func PBKDF2SHA512(password: Array<Int8>, salt: Array<UInt8>, iterations: Int = 2_048, keyLength: Int = 64) throws -> Array<UInt8> {
|
||||
var bytes = [UInt8](repeating: 0, count: keyLength)
|
||||
|
||||
try bytes.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) in
|
||||
let status = CCKeyDerivationPBKDF(
|
||||
CCPBKDFAlgorithm(kCCPBKDF2),
|
||||
password,
|
||||
password.count,
|
||||
salt,
|
||||
salt.count,
|
||||
CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512),
|
||||
UInt32(iterations),
|
||||
outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
|
||||
keyLength
|
||||
)
|
||||
guard status == kCCSuccess else {
|
||||
throw Error.invalidInput
|
||||
}
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue