Общий форум

Я пытаюсь создать хеш HMAC SHA-1 строки в Swift, но не могу понять, как взаимодействовать с API, поскольку он, кажется, не импортирует среду CommonCrypto. Я пробовал различные формы «import CommonCrypto» и создавал заголовочный файл моста, но ничто из этого не изменило ситуацию.

Странно то, что если я создам class Objective-C, я могу без проблем взаимодействовать с API, поэтому это похоже на Swift.

Также, если кто-нибудь может сказать мне, что эквивалент uint8_t digest[CC_SHA1_DIGEST_LENGTH] находится в Свифт, я был бы очень благодарен

Вы можете сделать это в Свифт. Просто убедитесь, что вы добавили #import в мостовой заголовок моста Objective-C.

Обновление: для Swift 4 см. Гораздо лучшее решение с помощью диспетчера пакетов Swift: https://github.com/jernejstrasner/SwiftCrypto

 enum CryptoAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 var HMACAlgorithm: CCHmacAlgorithm { var result: Int = 0 switch self { case .MD5: result = kCCHmacAlgMD5 case .SHA1: result = kCCHmacAlgSHA1 case .SHA224: result = kCCHmacAlgSHA224 case .SHA256: result = kCCHmacAlgSHA256 case .SHA384: result = kCCHmacAlgSHA384 case .SHA512: result = kCCHmacAlgSHA512 } return CCHmacAlgorithm(result) } var digestLength: Int { var result: Int32 = 0 switch self { case .MD5: result = CC_MD5_DIGEST_LENGTH case .SHA1: result = CC_SHA1_DIGEST_LENGTH case .SHA224: result = CC_SHA224_DIGEST_LENGTH case .SHA256: result = CC_SHA256_DIGEST_LENGTH case .SHA384: result = CC_SHA384_DIGEST_LENGTH case .SHA512: result = CC_SHA512_DIGEST_LENGTH } return Int(result) } } extension String { func hmac(algorithm: CryptoAlgorithm, key: String) -> String { let str = self.cStringUsingEncoding(NSUTF8StringEncoding) let strLen = Int(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let digestLen = algorithm.digestLength let result = UnsafeMutablePointer.alloc(digestLen) let keyStr = key.cStringUsingEncoding(NSUTF8StringEncoding) let keyLen = Int(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result) let digest = stringFromResult(result, length: digestLen) result.dealloc(digestLen) return digest } private func stringFromResult(result: UnsafeMutablePointer, length: Int) -> String { var hash = NSMutableString() for i in 0.. 

Попробуйте это для Swift 3.1 :

 enum CryptoAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 var HMACAlgorithm: CCHmacAlgorithm { var result: Int = 0 switch self { case .MD5: result = kCCHmacAlgMD5 case .SHA1: result = kCCHmacAlgSHA1 case .SHA224: result = kCCHmacAlgSHA224 case .SHA256: result = kCCHmacAlgSHA256 case .SHA384: result = kCCHmacAlgSHA384 case .SHA512: result = kCCHmacAlgSHA512 } return CCHmacAlgorithm(result) } var digestLength: Int { var result: Int32 = 0 switch self { case .MD5: result = CC_MD5_DIGEST_LENGTH case .SHA1: result = CC_SHA1_DIGEST_LENGTH case .SHA224: result = CC_SHA224_DIGEST_LENGTH case .SHA256: result = CC_SHA256_DIGEST_LENGTH case .SHA384: result = CC_SHA384_DIGEST_LENGTH case .SHA512: result = CC_SHA512_DIGEST_LENGTH } return Int(result) } } extension String { func hmac(algorithm: CryptoAlgorithm, key: String) -> String { let str = self.cString(using: String.Encoding.utf8) let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8)) let digestLen = algorithm.digestLength let result = UnsafeMutablePointer.allocate(capacity: digestLen) let keyStr = key.cString(using: String.Encoding.utf8) let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8)) CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result) let digest = stringFromResult(result: result, length: digestLen) result.deallocate(capacity: digestLen) return digest } private func stringFromResult(result: UnsafeMutablePointer, length: Int) -> String { let hash = NSMutableString() for i in 0.. 

Не забудьте добавить #import в Header.h

Swift может определить, как сопоставить объекты Obj-C, но не столько для прямых функций C. Apple предоставила некоторые привязки для таких вещей, как GCD и AudioToolbox, но не все. Кажется, у CommonCrypto пока нет правильных привязок.

В этом случае я бы рекомендовал писать собственные базовые обертки в Obj-C, а затем использовать эти classы-оболочки в Swift.

Например, вы можете создать class HMAC в Obj-C:

 // This enum is in HMAC.h typedef NS_ENUM(NSInteger, HMACAlgorithm) { SHA1, MD5, SHA256, SHA384, SHA512, SHA224 }; // Class methods here + (NSData *)calculateWithAlgorithm:(HMACAlgorithm)algorithm forKey:(const void *)key andData:(const void *)data { NSInteger digestLength = [self digestLengthForAlgorithm:algorithm]; unsigned char hmac[digestLength]; CCHmac(algorithm, &key, strlen(key), &data, strlen(data), &hmac); NSData *hmacBytes = [NSData dataWithBytes:hmac length:sizeof(hmac)]; return hmacBytes; } + (NSInteger)digestLengthForAlgorithm:(HMACAlgorithm)algorithm { switch (algorithm) { case MD5: return CC_MD5_DIGEST_LENGTH; case SHA1: return CC_SHA1_DIGEST_LENGTH; case SHA224: return CC_SHA224_DIGEST_LENGTH; case SHA256: return CC_SHA256_DIGEST_LENGTH; case SHA384: return CC_SHA384_DIGEST_LENGTH; case SHA512: return CC_SHA512_DIGEST_LENGTH; default: return 0; } } 

Затем в Свифте:

 class SwiftHMAC { // Swift will automatically pull the enum from Obj-C func calculate(algorithm:HMACAlgorithm, key:Byte[], data:Byte[]) -> Byte[] { let computedHMAC = HMAC.calculateWithAlgorithm(algorithm, forKey: key, andData: data) var rawBytes = Byte[](count: computedHMAC.length, repeatedValue: 0) computedHMAC.getBytes(&rawBytes) return rawBytes } } 

Просто не забудьте добавить #import "HMAC.h" в свой заголовок моста Swift, а также #import "<##Your-Project-Name##>-Swift.h" в файл реализации Obj-C (.m).

Ниже приведена исправленная версия того, что отправлено @ jernej-strasner

 enum HMACAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 func toCCEnum() -> CCHmacAlgorithm { var result: Int = 0 switch self { case .MD5: result = kCCHmacAlgMD5 case .SHA1: result = kCCHmacAlgSHA1 case .SHA224: result = kCCHmacAlgSHA224 case .SHA256: result = kCCHmacAlgSHA256 case .SHA384: result = kCCHmacAlgSHA384 case .SHA512: result = kCCHmacAlgSHA512 } return CCHmacAlgorithm(result) } func digestLength() -> Int { var result: CInt = 0 switch self { case .MD5: result = CC_MD5_DIGEST_LENGTH case .SHA1: result = CC_SHA1_DIGEST_LENGTH case .SHA224: result = CC_SHA224_DIGEST_LENGTH case .SHA256: result = CC_SHA256_DIGEST_LENGTH case .SHA384: result = CC_SHA384_DIGEST_LENGTH case .SHA512: result = CC_SHA512_DIGEST_LENGTH } return Int(result) } } extension String { func digest(algorithm: HMACAlgorithm, key: String) -> String! { let str = self.cStringUsingEncoding(NSUTF8StringEncoding) let strLen = UInt(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let digestLen = algorithm.digestLength() let result = UnsafeMutablePointer.alloc(digestLen) let keyStr = key.cStringUsingEncoding(NSUTF8StringEncoding) let keyLen = UInt(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) CCHmac(algorithm.toCCEnum(), keyStr!, keyLen, str!, strLen, result) var hash = NSMutableString() for i in 0.. 

Я хотел, чтобы вещи были минимальными. Избегайте дополнительной сложности создания универсального classа, который мог бы обрабатывать все различные типы дайджеста, и вместо этого просто иметь небольшой метод, который я мог бы упасть в class, если это необходимо. Я также предпочитаю избегать добавления расширений к основным classам.

Добавьте следующие -Bridging-Header.h файл -Bridging-Header.h :

 #import  

Затем в classе, который должен вызвать CCHmac() добавьте частный метод:

 private func hmac(string: NSString, key: NSData) -> NSData { let keyBytes = UnsafePointer(key.bytes) let data = string.cStringUsingEncoding(NSUTF8StringEncoding) let dataLen = Int(string.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let digestLen = Int(CC_SHA1_DIGEST_LENGTH) let result = UnsafeMutablePointer.alloc(digestLen) CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), keyBytes, key.length, data, dataLen, result); return NSData(bytes: result, length: digestLen) } 

Если мне нужен другой CCHmacAlgorithm я бы просто заменил две константы в этом методе соответствующими. В моем случае мне нужны kCCHmacAlgSHA256 и CC_SHA256_DIGEST_LENGTH .

Спасибо Jernej Strasner и другим за другие ответы, я просто хотел что-то более простое для моего дела.

после быстрого 1.2 заменить строки в func digest

 let strLen = UInt(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let keyLen = UInt(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) 

от

 let strLen = self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) let keyLen = key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) 

Это полный источник «Как импортировать CommonCrypto в проект Swift без заголовка Obj-c briging», измененный для Swift 3.0. Фактическая работа с кодом – «Михаэль Исаев».

 // // HMAC.swift // // Created by Mihael Isaev on 21.04.15. // Copyright (c) 2014 Mihael Isaev inc. All rights reserved. // // *********************************************************** // // How to import CommonCrypto in Swift project without Obj-c briging header // // To work around this create a directory called CommonCrypto in the root of the project using Finder. // In this directory create a file name module.map and copy the following into the file. // You will need to alter the paths to ensure they point to the headers on your system. // // module CommonCrypto [system] { // header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h" // export * // } // To make this module visible to Xcode, go to Build Settings, Swift Compiler – Search Paths // and set Import Paths to point to the directory that contains the CommonCrypto directory. // // You should now be able to use import CommonCrypto in your Swift code. // // You have to set the Import Paths in every project that uses your framework so that Xcode can find it. // // *********************************************************** // // Modification for Swift 3.0 by Sanjay Sampat on 04.Jan.2017 // // *********************************************************** import Foundation import CommonCrypto extension String { var md5: String { return HMAC.hash(inp: self, algo: HMACAlgo.MD5) } var sha1: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA1) } var sha224: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA224) } var sha256: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA256) } var sha384: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA384) } var sha512: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA512) } func aesEncrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? { if let keyData = key.data(using: String.Encoding.utf8), let data = self.data(using: String.Encoding.utf8), let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) { let keyLength = size_t(kCCKeySizeAES128) let operation: CCOperation = UInt32(kCCEncrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(options) var numBytesEncrypted :size_t = 0 let base64cryptStringOut = keyData.withUnsafeBytes {(keyBytes: UnsafePointer)->String? in return data.withUnsafeBytes {(dataBytes: UnsafePointer)->String? in let cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, iv, dataBytes, data.count, cryptData.mutableBytes, cryptData.length, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.length = Int(numBytesEncrypted) let base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters) return base64cryptString } else { return nil } } } return base64cryptStringOut } return nil } func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? { if let keyData = key.data(using: String.Encoding.utf8), let data = NSData(base64Encoded: self, options: .ignoreUnknownCharacters), let cryptData = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128) { let keyLength = size_t(kCCKeySizeAES128) let operation: CCOperation = UInt32(kCCDecrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(options) var numBytesEncrypted :size_t = 0 let unencryptedMessageOut = keyData.withUnsafeBytes {(keyBytes: UnsafePointer)->String? in let cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, iv, data.bytes, data.length, cryptData.mutableBytes, cryptData.length, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.length = Int(numBytesEncrypted) let unencryptedMessage = String(data: cryptData as Data, encoding:String.Encoding.utf8) return unencryptedMessage } else { return nil } } return unencryptedMessageOut } return nil } } public struct HMAC { static func hash(inp: String, algo: HMACAlgo) -> String { if let stringData = inp.data(using: String.Encoding.utf8, allowLossyConversion: false) { return hexStringFromData(input: digest(input: stringData as NSData, algo: algo)) } return "" } private static func digest(input : NSData, algo: HMACAlgo) -> NSData { let digestLength = algo.digestLength() var hash = [UInt8](repeating: 0, count: digestLength) switch algo { case .MD5: CC_MD5(input.bytes, UInt32(input.length), &hash) break case .SHA1: CC_SHA1(input.bytes, UInt32(input.length), &hash) break case .SHA224: CC_SHA224(input.bytes, UInt32(input.length), &hash) break case .SHA256: CC_SHA256(input.bytes, UInt32(input.length), &hash) break case .SHA384: CC_SHA384(input.bytes, UInt32(input.length), &hash) break case .SHA512: CC_SHA512(input.bytes, UInt32(input.length), &hash) break } return NSData(bytes: hash, length: digestLength) } private static func hexStringFromData(input: NSData) -> String { var bytes = [UInt8](repeating: 0, count: input.length) input.getBytes(&bytes, length: input.length) var hexString = "" for byte in bytes { hexString += String(format:"%02x", UInt8(byte)) } return hexString } } enum HMACAlgo { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 func digestLength() -> Int { var result: CInt = 0 switch self { case .MD5: result = CC_MD5_DIGEST_LENGTH case .SHA1: result = CC_SHA1_DIGEST_LENGTH case .SHA224: result = CC_SHA224_DIGEST_LENGTH case .SHA256: result = CC_SHA256_DIGEST_LENGTH case .SHA384: result = CC_SHA384_DIGEST_LENGTH case .SHA512: result = CC_SHA512_DIGEST_LENGTH } return Int(result) } } 

Ниже приведен пример использования.

  // TEST for Encryption and Decryption through HMAC Swift 3.0 let iv = "iv-salt-Sanjay--" // fixed 16 chars. let cryptoKeyString = "01234567890123456789012345678901" let originalString = "My Name is Sanjay Sampat, Password is [email protected]#" print("Original String: \(originalString)") if let encodedString = originalString.aesEncrypt(key: cryptoKeyString, iv: iv){ print("String Encoded: \(encodedString)") if let decryptedString = encodedString.aesDecrypt(key: cryptoKeyString, iv: iv) { print("String Decoded: \(decryptedString)") } else{ print("Decoding failed") } } else{ print("Encoding failed") } // Example To create sha1 from string let testString = "This is string to test sha1 hash string." let sha1Digest = testString.sha1 print("sha1-hash-string: \(sha1Digest)") 

Надеюсь, это может быть готовой ссылкой для некоторых пользователей, таких как я. 🙂

Для OS X (но не для iOS, SecTransform с этой записи, когда 9.3.1 является текущим), вы можете использовать SecTransform для вычисления HMAC SHA-1 в Swift без заголовка моста и без Objective-C. Ниже приведен пример использования первого теста HMAC-SHA-1 в RFC 2202 :

 import Foundation import Security var error: Unmanaged? let transform = SecDigestTransformCreate(kSecDigestHMACSHA1, 0, &error) let input = "Hi There" let inputData = input.dataUsingEncoding(NSUTF8StringEncoding)! let key = [UInt8](count: 20, repeatedValue: 0x0b) let keyData = key.withUnsafeBufferPointer { buffer in NSData(bytes: buffer.baseAddress, length: buffer.count) } SecTransformSetAttribute(transform, kSecTransformInputAttributeName, inputData, &error) SecTransformSetAttribute(transform, kSecDigestHMACKeyAttribute, keyData, &error) let outputData = SecTransformExecute(transform, &error) as! NSData 

Спасибо, Джерней Страснер за отличный ответ. Здесь я просто обновляю свой ответ для Swift 3.1:

 enum CryptoAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 var HMACAlgorithm: CCHmacAlgorithm { var result: Int = 0 switch self { case .MD5: result = kCCHmacAlgMD5 case .SHA1: result = kCCHmacAlgSHA1 case .SHA224: result = kCCHmacAlgSHA224 case .SHA256: result = kCCHmacAlgSHA256 case .SHA384: result = kCCHmacAlgSHA384 case .SHA512: result = kCCHmacAlgSHA512 } return CCHmacAlgorithm(result) } var digestLength: Int { var result: Int32 = 0 switch self { case .MD5: result = CC_MD5_DIGEST_LENGTH case .SHA1: result = CC_SHA1_DIGEST_LENGTH case .SHA224: result = CC_SHA224_DIGEST_LENGTH case .SHA256: result = CC_SHA256_DIGEST_LENGTH case .SHA384: result = CC_SHA384_DIGEST_LENGTH case .SHA512: result = CC_SHA512_DIGEST_LENGTH } return Int(result) } } extension String { func hmac(algorithm: CryptoAlgorithm, key: String) -> String { let str = self.cString(using: String.Encoding.utf8) let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8)) let digestLen = algorithm.digestLength let result = UnsafeMutablePointer.allocate(capacity: digestLen) let keyStr = key.cString(using: String.Encoding.utf8) let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8)) CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result) let digest = stringFromResult(result: result, length: digestLen) result.deallocate(capacity: digestLen) return digest } private func stringFromResult(result: UnsafeMutablePointer, length: Int) -> String { let hash = NSMutableString() for i in 0.. 

А также использовать его:

 func sha256(StringToSign : String, secretKey : String) -> String{ let hex = StringToSign.hmac(algorithm: .SHA256, key: secretKey) let hexData = hex.data(using: String.Encoding.utf8) let finalString = hexData?.base64EncodedString(options: [.lineLength64Characters]) return finalString! } 

Демоверсия Swift 4 в репозитории Github

  • От String до NSDate в Swift
  • Добавить салфетки для удаления UITableViewCell
  • Почему не конвертируется в ?
  • Избыточное сообщение об ошибке соответствия Swift 2
  • Программный переход на другой controller / сцену просмотра
  • Менеджер CLLocation в Swift, чтобы получить местоположение пользователя
  • Абстрактные classы в языке Swift
  • Как представить модальный поверх текущего вида в Swift
  • Дата метода DateFormatter (from: String) возвращает nil для определенных дат на определенных языках в Swift
  • Различия в синтаксисе NSDateComponents?
  • Могу ли я каким-то образом выполнить синхронный HTTP-запрос через NSURLSession в Swift
  • Давайте будем гением компьютера.