forked from sparkle-project/Sparkle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSignatures.swift
114 lines (93 loc) · 4.36 KB
/
Signatures.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//
// Created by Kornel on 23/12/2016.
// Copyright © 2016 Sparkle Project. All rights reserved.
//
import Foundation
struct PrivateKeys {
var privateDSAKey: SecKey?;
var privateEdKey: Data?;
var publicEdKey: Data?;
init(privateDSAKey: SecKey?, privateEdKey: Data?, publicEdKey: Data?) {
self.privateDSAKey = privateDSAKey;
self.privateEdKey = privateEdKey;
self.publicEdKey = publicEdKey;
}
}
func loadPrivateDSAKey(at privateKeyURL: URL) throws -> SecKey {
let data = try Data(contentsOf: privateKeyURL);
var cfitems: CFArray? = nil;
var format = SecExternalFormat.formatOpenSSL;
var type = SecExternalItemType.itemTypePrivateKey;
let status = SecItemImport(data as CFData, nil, &format, &type, SecItemImportExportFlags(rawValue: UInt32(0)), nil, nil, &cfitems);
if (status != errSecSuccess || cfitems == nil) {
print("Private DSA key file", privateKeyURL.path, "exists, but it could not be read. SecItemImport error", status);
throw NSError(domain: SUSparkleErrorDomain, code: Int(OSStatus(SUError.signatureError.rawValue)), userInfo: nil);
}
if (format != SecExternalFormat.formatOpenSSL || type != SecExternalItemType.itemTypePrivateKey) {
throw makeError(code: .signatureError, "Not an OpensSSL private key \(format) \(type)");
}
return (cfitems! as NSArray)[0] as! SecKey;
}
func loadPrivateDSAKey(named keyName: String, fromKeychainAt keychainURL: URL) throws -> SecKey {
var keychain: SecKeychain? = nil
guard SecKeychainOpen(keychainURL.path, &keychain) == errSecSuccess, keychain != nil else {
throw NSError(domain: SUSparkleErrorDomain, code: Int(OSStatus(SUError.signatureError.rawValue)), userInfo: nil)
}
let query: [CFString: CFTypeRef] = [
kSecClass: kSecClassKey,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
kSecAttrLabel: keyName as CFString,
kSecMatchLimit: kSecMatchLimitOne,
kSecUseKeychain: keychain!,
kSecReturnRef: kCFBooleanTrue
]
var item: CFTypeRef? = nil
guard SecItemCopyMatching(query as CFDictionary, &item) == errSecSuccess, item != nil else {
throw NSError(domain: SUSparkleErrorDomain, code: Int(OSStatus(SUError.signatureError.rawValue)), userInfo: nil)
}
return item! as! SecKey
}
func dsaSignature(path: URL, privateDSAKey: SecKey) throws -> String {
var error: Unmanaged<CFError>?;
let stream = InputStream(fileAtPath:path.path)!;
let dataReadTransform = SecTransformCreateReadTransformWithReadStream(stream);
let dataDigestTransform = SecDigestTransformCreate(kSecDigestSHA1, 20, nil);
guard let dataSignTransform = SecSignTransformCreate(privateDSAKey, &error) else {
print("can't use the key");
throw error!.takeRetainedValue();
}
let group = SecTransformCreateGroupTransform();
SecTransformConnectTransforms(dataReadTransform, kSecTransformOutputAttributeName, dataDigestTransform, kSecTransformInputAttributeName, group, &error);
if (error != nil) {
throw error!.takeRetainedValue();
}
SecTransformConnectTransforms(dataDigestTransform, kSecTransformOutputAttributeName, dataSignTransform, kSecTransformInputAttributeName, group, &error);
if (error != nil) {
throw error!.takeRetainedValue();
}
let result = SecTransformExecute(group, &error);
if (error != nil) {
throw error!.takeRetainedValue();
}
guard let resultData = result as? Data else {
throw makeError(code: .signatureError, "SecTransformExecute returned non-data");
}
return resultData.base64EncodedString();
}
func edSignature(path: URL, publicEdKey: Data, privateEdKey: Data) throws -> String {
assert(publicEdKey.count == 32)
assert(privateEdKey.count == 64)
let data = try Data.init(contentsOf: path, options: .mappedIfSafe);
let len = data.count;
var output = Data(count: 64);
output.withUnsafeMutableBytes({ (output: UnsafeMutablePointer<UInt8>) in
data.withUnsafeBytes({ (data: UnsafePointer<UInt8>) in
publicEdKey.withUnsafeBytes({ (publicEdKey: UnsafePointer<UInt8>) in
privateEdKey.withUnsafeBytes({ (privateEdKey: UnsafePointer<UInt8>) in
ed25519_sign(output, data, len, publicEdKey, privateEdKey)
});
});
})
});
return output.base64EncodedString();
}