KMRSAUtils.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. //
  2. // KMRSAUtils.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by User-Tangchao on 2024/9/2.
  6. //
  7. import Cocoa
  8. class KMRSAUtils: NSObject {
  9. // Configuration keys
  10. struct Config {
  11. /// Determines whether to add key hash to the keychain path when searching for a key
  12. /// or when adding a key to keychain
  13. static var useKeyHashes = true
  14. }
  15. // Base64 encode a block of data
  16. static fileprivate func base64Encode(_ data: Data) -> String {
  17. return data.base64EncodedString(options: [])
  18. }
  19. // Base64 decode a base64-ed string
  20. static fileprivate func base64Decode(_ strBase64: String) -> Data {
  21. let data = Data(base64Encoded: strBase64, options: [])
  22. return data!
  23. }
  24. // Encrypts data with a RSA key
  25. static public func encryptWithRSAKey(_ data: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
  26. let blockSize = SecKeyGetBlockSize(rsaKeyRef)
  27. let maxChunkSize = blockSize - 11
  28. var decryptedDataAsArray = [UInt8](repeating: 0, count: data.count / MemoryLayout<UInt8>.size)
  29. (data as NSData).getBytes(&decryptedDataAsArray, length: data.count)
  30. var encryptedData = [UInt8](repeating: 0, count: 0)
  31. var idx = 0
  32. while (idx < decryptedDataAsArray.count ) {
  33. var idxEnd = idx + maxChunkSize
  34. if ( idxEnd > decryptedDataAsArray.count ) {
  35. idxEnd = decryptedDataAsArray.count
  36. }
  37. var chunkData = [UInt8](repeating: 0, count: maxChunkSize)
  38. for i in idx..<idxEnd {
  39. chunkData[i-idx] = decryptedDataAsArray[i]
  40. }
  41. var encryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
  42. var encryptedDataLength = blockSize
  43. // let status = SecKeyEncrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &encryptedDataBuffer, &encryptedDataLength)
  44. // if ( status != noErr ) {
  45. // NSLog("Error while ecrypting: %i", status)
  46. return nil
  47. // }
  48. //let finalData = removePadding(encryptedDataBuffer)
  49. encryptedData += encryptedDataBuffer
  50. idx += maxChunkSize
  51. }
  52. return Data(bytes: UnsafePointer<UInt8>(encryptedData), count: encryptedData.count)
  53. }
  54. // Decrypt an encrypted data with a RSA key
  55. static public func decryptWithRSAKey(_ encryptedData: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
  56. let blockSize = SecKeyGetBlockSize(rsaKeyRef)
  57. var encryptedDataAsArray = [UInt8](repeating: 0, count: encryptedData.count / MemoryLayout<UInt8>.size)
  58. (encryptedData as NSData).getBytes(&encryptedDataAsArray, length: encryptedData.count)
  59. var decryptedData = [UInt8](repeating: 0, count: 0)
  60. var idx = 0
  61. while (idx < encryptedDataAsArray.count ) {
  62. var idxEnd = idx + blockSize
  63. if ( idxEnd > encryptedDataAsArray.count ) {
  64. idxEnd = encryptedDataAsArray.count
  65. }
  66. var chunkData = [UInt8](repeating: 0, count: blockSize)
  67. for i in idx..<idxEnd {
  68. chunkData[i-idx] = encryptedDataAsArray[i]
  69. }
  70. var decryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
  71. var decryptedDataLength = blockSize
  72. // let status = SecKeyDecrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &decryptedDataBuffer, &decryptedDataLength)
  73. // if ( status != noErr ) {
  74. return nil
  75. // }
  76. let finalData = removePadding(decryptedDataBuffer)
  77. decryptedData += finalData
  78. idx += blockSize
  79. }
  80. return Data(bytes: UnsafePointer<UInt8>(decryptedData), count: decryptedData.count)
  81. }
  82. static fileprivate func removePadding(_ data: [UInt8]) -> [UInt8] {
  83. var idxFirstZero = -1
  84. var idxNextZero = data.count
  85. for i in 0..<data.count {
  86. if ( data[i] == 0 ) {
  87. if ( idxFirstZero < 0 ) {
  88. idxFirstZero = i
  89. } else {
  90. idxNextZero = i
  91. break
  92. }
  93. }
  94. }
  95. var newData = [UInt8](repeating: 0, count: idxNextZero-idxFirstZero-1)
  96. for i in idxFirstZero+1..<idxNextZero {
  97. newData[i-idxFirstZero-1] = data[i]
  98. }
  99. return newData
  100. }
  101. // Verify that the supplied key is in fact a X509 public key and strip the header
  102. // On disk, a X509 public key file starts with string "-----BEGIN PUBLIC KEY-----",
  103. // and ends with string "-----END PUBLIC KEY-----"
  104. static fileprivate func stripPublicKeyHeader(_ pubkey: Data) -> Data? {
  105. if ( pubkey.count == 0 ) {
  106. return nil
  107. }
  108. var keyAsArray = [UInt8](repeating: 0, count: pubkey.count / MemoryLayout<UInt8>.size)
  109. (pubkey as NSData).getBytes(&keyAsArray, length: pubkey.count)
  110. var idx = 0
  111. if (keyAsArray[idx] != 0x30) {
  112. return nil
  113. }
  114. idx += 1
  115. if (keyAsArray[idx] > 0x80) {
  116. idx += Int(keyAsArray[idx]) - 0x80 + 1
  117. } else {
  118. idx += 1
  119. }
  120. let seqiod = [UInt8](arrayLiteral: 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00)
  121. for i in idx..<idx+15 {
  122. if ( keyAsArray[i] != seqiod[i-idx] ) {
  123. return nil
  124. }
  125. }
  126. idx += 15
  127. if (keyAsArray[idx] != 0x03) {
  128. return nil
  129. }
  130. idx += 1
  131. if (keyAsArray[idx] > 0x80) {
  132. idx += Int(keyAsArray[idx]) - 0x80 + 1;
  133. } else {
  134. idx += 1
  135. }
  136. if (keyAsArray[idx] != 0x00) {
  137. return nil
  138. }
  139. idx += 1
  140. //return pubkey.subdata(in: idx..<keyAsArray.count - idx)
  141. //return pubkey.subdata(in: NSMakeRange(idx, keyAsArray.count - idx))
  142. return pubkey.subdata(in: NSMakeRange(idx, keyAsArray.count - idx).toRange()!)
  143. }
  144. // Verify that the supplied key is in fact a PEM RSA private key key and strip the header
  145. // On disk, a PEM RSA private key file starts with string "-----BEGIN RSA PRIVATE KEY-----",
  146. // and ends with string "-----END RSA PRIVATE KEY-----"
  147. static fileprivate func stripPrivateKeyHeader(_ privkey: Data) -> Data? {
  148. if ( privkey.count == 0 ) {
  149. return nil
  150. }
  151. var keyAsArray = [UInt8](repeating: 0, count: privkey.count / MemoryLayout<UInt8>.size)
  152. (privkey as NSData).getBytes(&keyAsArray, length: privkey.count)
  153. //magic byte at offset 22, check if it's actually ASN.1
  154. var idx = 22
  155. if ( keyAsArray[idx] != 0x04 ) {
  156. return nil
  157. }
  158. idx += 1
  159. //now we need to find out how long the key is, so we can extract the correct hunk
  160. //of bytes from the buffer.
  161. var len = Int(keyAsArray[idx])
  162. idx += 1
  163. let det = len & 0x80 //check if the high bit set
  164. if (det == 0) {
  165. //no? then the length of the key is a number that fits in one byte, (< 128)
  166. len = len & 0x7f
  167. } else {
  168. //otherwise, the length of the key is a number that doesn't fit in one byte (> 127)
  169. var byteCount = Int(len & 0x7f)
  170. if (byteCount + idx > privkey.count) {
  171. return nil
  172. }
  173. //so we need to snip off byteCount bytes from the front, and reverse their order
  174. var accum: UInt = 0
  175. var idx2 = idx
  176. idx += byteCount
  177. while (byteCount > 0) {
  178. //after each byte, we shove it over, accumulating the value into accum
  179. accum = (accum << 8) + UInt(keyAsArray[idx2])
  180. idx2 += 1
  181. byteCount -= 1
  182. }
  183. // now we have read all the bytes of the key length, and converted them to a number,
  184. // which is the number of bytes in the actual key. we use this below to extract the
  185. // key bytes and operate on them
  186. len = Int(accum)
  187. }
  188. //return privkey.subdata(in: idx..<len)
  189. //return privkey.subdata(in: NSMakeRange(idx, len))
  190. return privkey.subdata(in: NSMakeRange(idx, len).toRange()!)
  191. }
  192. // Delete any existing RSA key from keychain
  193. static public func deleteRSAKeyFromKeychain(_ tagName: String) {
  194. let queryFilter: [String: AnyObject] = [
  195. String(kSecClass) : kSecClassKey,
  196. String(kSecAttrKeyType) : kSecAttrKeyTypeRSA,
  197. String(kSecAttrApplicationTag): tagName as AnyObject
  198. ]
  199. SecItemDelete(queryFilter as CFDictionary)
  200. }
  201. // Get a SecKeyRef from keychain
  202. static public func getRSAKeyFromKeychain(_ tagName: String) -> SecKey? {
  203. let queryFilter: [String: AnyObject] = [
  204. String(kSecClass) : kSecClassKey,
  205. String(kSecAttrKeyType) : kSecAttrKeyTypeRSA,
  206. String(kSecAttrApplicationTag): tagName as AnyObject,
  207. //String(kSecAttrAccessible) : kSecAttrAccessibleWhenUnlocked,
  208. String(kSecReturnRef) : true as AnyObject
  209. ]
  210. var keyPtr: AnyObject?
  211. let result = SecItemCopyMatching(queryFilter as CFDictionary, &keyPtr)
  212. if ( result != noErr || keyPtr == nil ) {
  213. return nil
  214. }
  215. return keyPtr as! SecKey?
  216. }
  217. // Add a RSA private key to keychain and return its SecKeyRef
  218. // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
  219. static public func addRSAPrivateKey(_ privkeyBase64: String, tagName: String) -> SecKey? {
  220. return addRSAPrivateKey(privkey: base64Decode(privkeyBase64), tagName: tagName)
  221. }
  222. static fileprivate func addRSAPrivateKey(privkey: Data, tagName: String) -> SecKey? {
  223. // Delete any old lingering key with the same tag
  224. deleteRSAKeyFromKeychain(tagName)
  225. let privkeyData = stripPrivateKeyHeader(privkey)
  226. if ( privkeyData == nil ) {
  227. return nil
  228. }
  229. // Add persistent version of the key to system keychain
  230. // var prt: AnyObject?
  231. let queryFilter = [
  232. // String(kSecClass) : kSecClassKey,
  233. // String(kSecAttrKeyType) : kSecAttrKeyTypeRSA,
  234. // String(kSecAttrApplicationTag) : tagName,
  235. //String(kSecAttrAccessible) : kSecAttrAccessibleWhenUnlocked,
  236. String(kSecValueData) : privkeyData!,
  237. String(kSecAttrKeyClass) : kSecAttrKeyClassPrivate,
  238. // String(kSecReturnPersistentRef): true
  239. ] as [String : Any]
  240. let result = SecItemAdd(queryFilter as CFDictionary, nil)
  241. if ((result != noErr) && (result != errSecDuplicateItem)) {
  242. return nil
  243. }
  244. return getRSAKeyFromKeychain(tagName)
  245. }
  246. // Add a RSA pubic key to keychain and return its SecKeyRef
  247. // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
  248. static public func addRSAPublicKey(_ pubkeyBase64: String, tagName: String) -> SecKey? {
  249. return addRSAPublicKey(pubkey: base64Decode(pubkeyBase64), tagName: tagName)
  250. }
  251. static fileprivate func addRSAPublicKey(pubkey: Data, tagName: String) -> SecKey? {
  252. // Delete any old lingering key with the same tag
  253. deleteRSAKeyFromKeychain(tagName)
  254. let pubkeyData = stripPublicKeyHeader(pubkey)
  255. if ( pubkeyData == nil ) {
  256. return nil
  257. }
  258. // Add persistent version of the key to system keychain
  259. //var prt1: Unmanaged<AnyObject>?
  260. let queryFilter = [
  261. String(kSecClass) : kSecClassKey,
  262. String(kSecAttrKeyType) : kSecAttrKeyTypeRSA,
  263. String(kSecAttrApplicationTag) : tagName,
  264. String(kSecValueData) : pubkeyData!,
  265. String(kSecAttrKeyClass) : kSecAttrKeyClassPublic,
  266. String(kSecReturnPersistentRef): true
  267. ] as [String : Any]
  268. let result = SecItemAdd(queryFilter as CFDictionary, nil)
  269. if ((result != noErr) && (result != errSecDuplicateItem)) {
  270. return nil
  271. }
  272. return getRSAKeyFromKeychain(tagName)
  273. }
  274. // Encrypt data with a RSA private key
  275. // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
  276. // NOT WORKING YET!
  277. static public func encryptWithRSAPrivateKey(_ data: Data, privkeyBase64: String, keychainTag: String) -> Data? {
  278. let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(privkeyBase64.hashValue) : "")
  279. var keyRef = getRSAKeyFromKeychain(myKeychainTag)
  280. if ( keyRef == nil ) {
  281. keyRef = addRSAPrivateKey(privkeyBase64, tagName: myKeychainTag)
  282. }
  283. if ( keyRef == nil ) {
  284. return nil
  285. }
  286. return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
  287. }
  288. // Encrypt data with a RSA public key
  289. // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
  290. static public func encryptWithRSAPublicKey(_ data: Data, pubkeyBase64: String, keychainTag: String) -> Data? {
  291. let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(pubkeyBase64.hashValue) : "")
  292. var keyRef = getRSAKeyFromKeychain(myKeychainTag)
  293. if ( keyRef == nil ) {
  294. keyRef = addRSAPublicKey(pubkeyBase64, tagName: myKeychainTag)
  295. }
  296. if ( keyRef == nil ) {
  297. return nil
  298. }
  299. return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
  300. }
  301. // Decrypt an encrypted data with a RSA private key
  302. // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
  303. static public func decryptWithRSAPrivateKey(_ encryptedData: Data, privkeyBase64: String, keychainTag: String) -> Data? {
  304. let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(privkeyBase64.hashValue) : "")
  305. var keyRef = getRSAKeyFromKeychain(myKeychainTag)
  306. if ( keyRef == nil ) {
  307. keyRef = addRSAPrivateKey(privkeyBase64, tagName: myKeychainTag)
  308. }
  309. if ( keyRef == nil ) {
  310. return nil
  311. }
  312. return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: SecPadding())
  313. }
  314. // Decrypt an encrypted data with a RSA public key
  315. // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
  316. static public func decryptWithRSAPublicKey(_ encryptedData: Data, pubkeyBase64: String, keychainTag: String) -> Data? {
  317. let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(pubkeyBase64.hashValue) : "")
  318. var keyRef = getRSAKeyFromKeychain(myKeychainTag)
  319. if ( keyRef == nil ) {
  320. keyRef = addRSAPublicKey(pubkeyBase64, tagName: myKeychainTag)
  321. }
  322. if ( keyRef == nil ) {
  323. return nil
  324. }
  325. return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: SecPadding())
  326. }
  327. }