-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit eab1b7e
Showing
12 changed files
with
779 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.DS_Store | ||
/.build | ||
/Packages | ||
/*.xcodeproj |
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,16 @@ | ||
{ | ||
"object": { | ||
"pins": [ | ||
{ | ||
"package": "Datable", | ||
"repositoryURL": "https://github.com/OperatorFoundation/Datable.git", | ||
"state": { | ||
"branch": null, | ||
"revision": "cc91e8b71dbbe125a19090c26f4e8c21b6d0dcb4", | ||
"version": "1.0.5" | ||
} | ||
} | ||
] | ||
}, | ||
"version": 1 | ||
} |
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,28 @@ | ||
// swift-tools-version:4.2 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "ReplicantSwift", | ||
products: [ | ||
// Products define the executables and libraries produced by a package, and make them visible to other packages. | ||
.library( | ||
name: "ReplicantSwift", | ||
targets: ["ReplicantSwift"]), | ||
], | ||
dependencies: [ | ||
// Dependencies declare other packages that this package depends on. | ||
.package(url: "https://github.com/OperatorFoundation/Datable.git", from: "1.0.5"), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package. A target can define a module or a test suite. | ||
// Targets can depend on other targets in this package, and on products in packages which this package depends on. | ||
.target( | ||
name: "ReplicantSwift", | ||
dependencies: ["Datable"]), | ||
.testTarget( | ||
name: "ReplicantSwiftTests", | ||
dependencies: ["ReplicantSwift"]), | ||
] | ||
) |
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,3 @@ | ||
# ReplicantSwift | ||
|
||
A description of this package. |
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,17 @@ | ||
// | ||
// Constants.swift | ||
// ReplicantSwift | ||
// | ||
// Created by Adelita Schule on 11/9/18. | ||
// | ||
|
||
import Foundation | ||
|
||
let chunkSize = 4096 | ||
let aesOverhead = 81 | ||
let bufferSize = chunkSize - aesOverhead | ||
let keySize = 64 | ||
let keyDataSize = keySize + 1 | ||
let cryptoHandshakeSize = chunkSize | ||
let cryptoHandshakePaddingSize = cryptoHandshakeSize - keySize | ||
let responseSize = chunkSize |
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,64 @@ | ||
// | ||
// CryptoHandshake.swift | ||
// ReplicantSwift | ||
// | ||
// Created by Adelita Schule on 11/9/18. | ||
// | ||
|
||
import Foundation | ||
import Datable | ||
import CommonCrypto | ||
|
||
/** | ||
The client will need to know the server’s public key as part of the configuration. The server will not know the client’s public key, so the first thing the client will need to send is it’s public key. After that, it will just send encrypted data. Please note that the client public key when exported to a Data from CommonCrypto will be 65 bytes, where the first byte is always 4. This should be stripped off to remove the redundant 4 and just the remaining 64 bytes should be sent. The key size should then be padded to be the size of one chunk. | ||
The server will then send a response which is the size of one chunk, and which contains random bytes that should be discarded. | ||
*/ | ||
class CryptoHandshake: NSObject | ||
{ | ||
let encryptor = Encryption() | ||
|
||
/// The client will need to know the server’s public key as part of the configuration. | ||
var serverPublicKey: Data | ||
|
||
/// The client public key when exported to a Data from CommonCrypto will be 65 bytes, where the first byte is always 4. This should be stripped off to remove the redundant 4 and just the remaining 64 bytes should be sent. The key size should then be padded to be the size of one chunk. | ||
var clientPublicKey: Data | ||
|
||
init?(withKeyData clientKeyData: Data, andServerKeyData serverKeyData: Data) | ||
{ | ||
guard let allDressedUp = encryptor.cleanAndPadKey(keyData: clientKeyData) | ||
else | ||
{ | ||
return nil | ||
} | ||
|
||
clientPublicKey = allDressedUp | ||
serverPublicKey = serverKeyData | ||
} | ||
|
||
init?(withKey clientKey: SecKey, andServerKeyData serverKeyData: Data) | ||
{ | ||
var error: Unmanaged<CFError>? | ||
|
||
// Encode public key as data | ||
guard let clientPublicData = SecKeyCopyExternalRepresentation(clientKey, &error) as Data? | ||
else | ||
{ | ||
print("\nUnable to generate public key external representation: \(error!.takeRetainedValue() as Error)\n") | ||
return nil | ||
} | ||
|
||
//FIXME: Padding | ||
guard let cleanClientPublicData = encryptor.cleanAndPadKey(keyData: clientPublicData) | ||
else | ||
{ | ||
return nil | ||
} | ||
|
||
clientPublicKey = cleanClientPublicData | ||
serverPublicKey = serverKeyData | ||
} | ||
|
||
|
||
} | ||
|
||
|
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,219 @@ | ||
// | ||
// Encryption.swift | ||
// ReplicantSwift | ||
// | ||
// Created by Adelita Schule on 11/9/18. | ||
// | ||
|
||
import Foundation | ||
import Security | ||
import CommonCrypto | ||
|
||
class Encryption: NSObject | ||
{ | ||
let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorX963SHA256AESGCM | ||
//var privateKey: SecKey | ||
|
||
// public init?(withPrivateKey initKey: Data?) | ||
// { | ||
// if let providedKey = initKey | ||
// { | ||
// guard let secKey = Encryption.decodeKey(fromData: providedKey) | ||
// else | ||
// { | ||
// print("\nFailed to initialize Replicant: Unable to create SecKey from key data provided.") | ||
// return nil | ||
// } | ||
// | ||
// privateKey = secKey | ||
// } | ||
// else | ||
// { | ||
// guard let newKey = Encryption.generatePrivateKey() | ||
// else | ||
// { | ||
// return nil | ||
// } | ||
// | ||
// privateKey = newKey | ||
// } | ||
// | ||
// } | ||
|
||
|
||
func generatePrivateKey() -> SecKey? | ||
{ | ||
// Generate private key | ||
let tag = "com.example.keys.mykey".data(using: .utf8)! | ||
|
||
let access = SecAccessControlCreateWithFlags(kCFAllocatorDefault, | ||
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, | ||
.privateKeyUsage, | ||
nil)! | ||
|
||
let privateKeyAttributes: [String: Any] = [ | ||
kSecAttrIsPermanent as String: true, | ||
kSecAttrApplicationTag as String: tag | ||
/*kSecAttrAccessControl as String: access*/ | ||
] | ||
|
||
let attributes: [String: Any] = [ | ||
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, | ||
kSecAttrKeySizeInBits as String: 256, | ||
/*kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,*/ | ||
kSecPrivateKeyAttrs as String: privateKeyAttributes | ||
] | ||
|
||
var error: Unmanaged<CFError>? | ||
guard let alicePrivate = SecKeyCreateRandomKey(attributes as CFDictionary, &error) | ||
else | ||
{ | ||
print("\nUnable to generate the client private key: \(error!.takeRetainedValue() as Error)\n") | ||
return nil | ||
} | ||
|
||
return alicePrivate | ||
} | ||
|
||
/** | ||
Generate a public key from the provided private key and encodes it as data. | ||
|
||
- Returns: optional, encoded key as data | ||
*/ | ||
func generatePublicKey(usingPrivateKey privateKey: SecKey) -> Data? | ||
{ | ||
var error: Unmanaged<CFError>? | ||
|
||
guard let alicePublic = SecKeyCopyPublicKey(privateKey) | ||
else | ||
{ | ||
print("\nUnable to generate a public key from the provided private key.\n") | ||
return nil | ||
} | ||
|
||
// Encode public key as data | ||
guard let alicePublicData = SecKeyCopyExternalRepresentation(alicePublic, &error) as Data? | ||
else | ||
{ | ||
print("\nUnable to generate public key external representation: \(error!.takeRetainedValue() as Error)\n") | ||
return nil | ||
} | ||
|
||
return alicePublicData | ||
} | ||
|
||
/// Decode data to get public key | ||
static func decodeKey(fromData publicKeyData: Data) -> SecKey? | ||
{ | ||
var error: Unmanaged<CFError>? | ||
|
||
let options: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeEC, | ||
kSecAttrKeyClass as String: kSecAttrKeyClassPublic, | ||
kSecAttrKeySizeInBits as String: 256] | ||
|
||
guard let decodedBobPublicKey = SecKeyCreateWithData(publicKeyData as CFData, options as CFDictionary, &error) | ||
else | ||
{ | ||
print("\nUnable to decode server public key: \(error!.takeRetainedValue() as Error)\n") | ||
return nil | ||
} | ||
|
||
return decodedBobPublicKey | ||
} | ||
|
||
/// Encrypt payload | ||
func encrypt(payload: Data, usingServerKey serverPublicKey: SecKey) -> Data? | ||
{ | ||
var error: Unmanaged<CFError>? | ||
|
||
guard let cipherText = SecKeyCreateEncryptedData(serverPublicKey, algorithm, payload as CFData, &error) as Data? | ||
else | ||
{ | ||
print("\nUnable to encrypt payload: \(error!.takeRetainedValue() as Error)\n") | ||
return nil | ||
} | ||
|
||
return cipherText | ||
} | ||
|
||
/// Decrypt payload | ||
/// - Parameter payload: Data | ||
/// - Parameter privateKey: SecKey | ||
func decrypt(payload: Data, usingPrivateKey privateKey: SecKey) -> Data? | ||
{ | ||
var error: Unmanaged<CFError>? | ||
|
||
guard let decryptedText = SecKeyCreateDecryptedData(privateKey, algorithm, payload as CFData, &error) as Data? | ||
else | ||
{ | ||
print("\nUnable to decrypt payload: \(error!.takeRetainedValue() as Error)\n") | ||
return nil | ||
} | ||
|
||
return decryptedText | ||
} | ||
|
||
func cleanKeyData(keyData: Data) -> Data? | ||
{ | ||
if keyData.count == keyDataSize | ||
{ | ||
if keyData.first! == 4 | ||
{ | ||
// Strip the redundant 4 from the key data | ||
let cleanKey = keyData.dropFirst() | ||
return cleanKey | ||
} | ||
else | ||
{ | ||
print("\nFailed to clean key: Data was 65 bytes but the first byte was not 4.\n") | ||
return nil | ||
} | ||
} | ||
else if keyData.count == keySize | ||
{ | ||
print("\nReturning unchanged key data, the byte count was already 64.\n") | ||
return keyData | ||
} | ||
else | ||
{ | ||
print("Failed to clean key data: unexpected byte count of \(keyData.count)") | ||
return nil | ||
} | ||
} | ||
|
||
func getKeyPadding() -> Data? | ||
{ | ||
var bytes = [UInt8](repeating: 0, count: chunkSize - keySize) | ||
let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes) | ||
|
||
if status == errSecSuccess | ||
{ | ||
// Always test the status. | ||
print(bytes) | ||
// Prints something different every time you run. | ||
return Data(array: bytes) | ||
} | ||
else | ||
{ | ||
print("\nFailed to gnerate padding: \(status)\n") | ||
return nil | ||
} | ||
} | ||
|
||
func cleanAndPadKey(keyData: Data) -> Data? | ||
{ | ||
guard let cleanKey = cleanKeyData(keyData: keyData) | ||
else | ||
{ | ||
return nil | ||
} | ||
|
||
guard let padding = getKeyPadding() | ||
else | ||
{ | ||
return nil | ||
} | ||
|
||
return cleanKey + padding | ||
} | ||
} |
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,14 @@ | ||
import Foundation | ||
import Security | ||
import CommonCrypto | ||
|
||
/** | ||
* [Using Keys For Encryption](https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/using_keys_for_encryption), | ||
* [Storing Keys in the Secure Enclave](https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/storing_keys_in_the_secure_enclave), | ||
* [seckeyalgorithm](https://developer.apple.com/documentation/security/seckeyalgorithm/2091905-eciesencryptioncofactorx963sha25) | ||
*/ | ||
public struct Replicant | ||
{ | ||
|
||
|
||
} |
Oops, something went wrong.