Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在swift中实现HMAC和SHA1加密_Ios_Swift_Xcode6 - Fatal编程技术网

Ios 在swift中实现HMAC和SHA1加密

Ios 在swift中实现HMAC和SHA1加密,ios,swift,xcode6,Ios,Swift,Xcode6,我对Swift比较陌生,我一直在使用HMAC和SHA1进行加密。我找到了下面的答案,但我不知道如何正确地实现它。任何帮助都将是惊人的。我使用了这个模块,我将它作为一个框架添加到我的项目中: 我还为SHA256.swift添加了以下字符串扩展名: public extension String { func sha256(key: String) -> String { let inputData: NSData = self.dataUsingEncoding(

我对Swift比较陌生,我一直在使用HMAC和SHA1进行加密。我找到了下面的答案,但我不知道如何正确地实现它。任何帮助都将是惊人的。

我使用了这个模块,我将它作为一个框架添加到我的项目中:

我还为SHA256.swift添加了以下
字符串
扩展名:

public extension String {

    func sha256(key: String) -> String {
        let inputData: NSData = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let keyData: NSData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!

        let algorithm = HMACAlgorithm.SHA256
        let digestLen = algorithm.digestLength()
        let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)

        CCHmac(algorithm.toCCEnum(), keyData.bytes, UInt(keyData.length), inputData.bytes, UInt(inputData.length), result)
        let data = NSData(bytes: result, length: digestLen)
        result.destroy()
        return data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
    }

}

问题解决了!首先,我没有正确使用字符串函数。。。我的结局是:

    let hmacResult:String = "myStringToHMAC".hmac(HMACAlgorithm.SHA1, key: "myKey")
然后我忘记了我需要对hmac结果进行base64编码。所以我修改了我问题中的字符串函数

enum HMACAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    func toCCHmacAlgorithm() -> 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 hmac(algorithm: HMACAlgorithm, key: String) -> String {
        let cKey = key.cStringUsingEncoding(NSUTF8StringEncoding)
        let cData = self.cStringUsingEncoding(NSUTF8StringEncoding)
        var result = [CUnsignedChar](count: Int(algorithm.digestLength()), repeatedValue: 0)
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, strlen(cKey!), cData!, strlen(cData!), &result)
        var hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
        var hmacBase64 = hmacData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding76CharacterLineLength)
        return String(hmacBase64)
    }
}
这是给我的正确结果

lGCtbW+DNHFraNoxPGK3trgM/98=

如果希望以十六进制格式显示相同的结果,可以使用以下扩展名:

extension String {
    func hmac(algorithm: HMACAlgorithm, key: String) -> String {
        let cKey = key.cStringUsingEncoding(NSUTF8StringEncoding)
        let cData = self.cStringUsingEncoding(NSUTF8StringEncoding)
        var result = [CUnsignedChar](count: Int(algorithm.digestLength()), repeatedValue: 0)
        let length : Int = Int(strlen(cKey!))
        let data : Int = Int(strlen(cData!))
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!,length , cData!, data, &result)

        let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))

        var bytes = [UInt8](count: hmacData.length, repeatedValue: 0)
        hmacData.getBytes(&bytes, length: hmacData.length)

        var hexString = ""
        for byte in bytes {
            hexString += String(format:"%02hhx", UInt8(byte))
        }
        return hexString
    }
}

以下是@David Wood针对Swift 3更新的解决方案:

enum HMACAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    func toCCHmacAlgorithm() -> 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 hmac(algorithm: HMACAlgorithm, key: String) -> String {
        let cKey = key.cString(using: String.Encoding.utf8)
        let cData = self.cString(using: String.Encoding.utf8)
        var result = [CUnsignedChar](repeating: 0, count: Int(algorithm.digestLength()))
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, Int(strlen(cKey!)), cData!, Int(strlen(cData!)), &result)
        let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
        let hmacBase64 = hmacData.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength76Characters)
        return String(hmacBase64)
    }
}

// usage:
let hmacResult: String = "myStringToHMAC".hmac(algorithm: HMACAlgorithm.SHA1, key: "foo")

我检查了上面的答案,发现它太长了

解决方案:我找到了第三方:

使用pod:
pod'IDZSwiftCommonCrypto'

并使用以下功能实现所需输出:

func getHMacSHA1(forMessage message: String, key: String) -> String? {
    let hMacVal = HMAC(algorithm: HMAC.Algorithm.sha1, key: key).update(string: message)?.final()
    if let encryptedData = hMacVal {
        let decData = NSData(bytes: encryptedData, length: Int(encryptedData.count))
        let base64String = decData.base64EncodedString(options: .lineLength64Characters)
        print("base64String: \(base64String)")
        return base64String
    } else {
        return nil
    }
}
要查看结果,请使用以下网站:

在Swift 4.0中测试


以下是如何创建Swift 4扩展名:

桥接头文件

#import <CommonCrypto/CommonCrypto.h>
extension String {

    func hmac(key: String) -> String {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), key, key.count, self, self.count, &digest)
        let data = Data(bytes: digest)
        return data.map { String(format: "%02hhx", $0) }.joined()
    }

}
let result = "test".hmac(key: "test")
示例

#import <CommonCrypto/CommonCrypto.h>
extension String {

    func hmac(key: String) -> String {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), key, key.count, self, self.count, &digest)
        let data = Data(bytes: digest)
        return data.map { String(format: "%02hhx", $0) }.joined()
    }

}
let result = "test".hmac(key: "test")
结果

0c94515c15e5095b8a87a50ba0df3bf38ed05fe6

将原始字节用于密钥和消息,而不是编码为utf8:

    static func getHmac_X_Sha1() -> [UInt8] {

        let msg:[UInt8] = message_uint8;
        let msgLen = message_uint8.count;
        let digestLen = Int(CC_SHA1_DIGEST_LENGTH)
        let digest = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        let keyStr:[UInt8] = key_uint8
        let keyLen = key_uint8.count

        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), keyStr, keyLen, msg, msgLen, digest)


        //Build a hex string of result
        let hash_hex_string = NSMutableString()
        for i in 0..<digestLen {
            hash_hex_string.appendFormat("%02x", result[i])
         }
         //print(hash_hex_string)
         result.deallocate()

         // Resolve hash_hex_string to byte array
         let hash_bytes:[UInt8] = hexStringToBytes(String(hash_hex_string))
         return hash_bytes
     }



    //Return a byte array from hex string input
     private static func hexStringToBytes(_ string: String) -> [UInt8]? {
        let length = string.characters.count
        if length & 1 != 0 {
            return nil
        }
        var bytes = [UInt8]()
        bytes.reserveCapacity(length/2)
        var index = string.startIndex
        for _ in 0..<length/2 {
            let nextIndex = string.index(index, offsetBy: 2)
            if let b = UInt8(string[index..<nextIndex], radix: 16) {
                bytes.append(b)
            } else {
                return nil
            }
            index = nextIndex
        }
        return bytes
     }
静态函数getHmac_X_Sha1()->[UInt8]{
let msg:[UInt8]=消息\u UInt8;
让msgLen=message_uint8.count;
设digestLen=Int(CC\u SHA1\u DIGEST\u长度)
let digest=unsafemeutablepointer.allocate(容量:digestLen)
让keyStr:[UInt8]=键UInt8
设keyLen=key\u uint8.count
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1)、keyStr、keyLen、msg、msgLen、digest)
//生成结果的十六进制字符串
让hash_hex_string=NSMutableString()
对于0中的i..[UInt8]{
让长度=string.characters.count
如果长度&1!=0{
归零
}
变量字节=[UInt8]()
字节。保留容量(长度/2)
var index=string.startIndex

对于Swift 4中的uu0..,您需要库CommonCrypto

用途:

print("HMAC_SHA256:".hmac(key: "MyKey"))
结果:

6GM2evJeNZYdP3OjPcKmg8TDzILSQAjy4NGhCHnBH5M=


我使用了这个精确的答案,它对我很有用。你能描述一下你遇到的问题吗?也许是复制和粘贴代码,然后使用
–hmac(算法:key:)
方法在您的
字符串上
对象…?我设法在Objective-C中找到了解决方案,我想我缺少了与之等价的:@interface HashSHA1:NSObject-(NSString*)hashedValue:(NSString*)键和数据:(NSString*)数据;HMAC和SHA1不是加密。普通加密可以从Swift使用,并提供您所需的原语。您链接到的答案是Swift,并且@maksimov也提供了答案。将使用此方法的代码添加到问题中,有人可能会发现问题。为什么在使用简单方法时使用扩展?此方法是否有效ally属于String类的一部分?嗯,应该有比“为什么不”更好的理由。如果没有明确的理由和优势将其作为扩展,那么就不要。需要回答的问题是:“这是
String
类的自然和预期部分吗?”我希望在字符串类中找到所有加密的东西吗?当然,你是对的。在我的例子中,这是一个小的原型项目,我刚开始使用Swift,我想“哦,看,我可以扩展字符串类并制作这个快捷方式,哇!”。在这个实验中没有人受伤。:-)我得到一个错误“参数计数必须在重复之前”。这个错误在hmac函数的第3行中报告。我使用的是Xcode 8.2.1和Swift 3。@JayprakashDubey听起来像是你输入了错别字?我在几个项目中运行了这段代码。你提到的错误听起来像是在这个项目上s initializer,这在上面的代码中是正确的:谢谢!为我工作只需要导入var result=[CUnsignedChar](count:Int(algorithm.digestLength()),repeatedValue:0)新swiftAre中是否有错误?您确定得到了正确的结果吗?您不应该得到它,因为您在最后传递了密钥和数据,并附加了一个
\0
,因为您使用的是cstring(以null结尾)没有得到相同的结果。我得到了85afQardtIk0rRWRlQ10qrL/STc=@user3745635您需要导入Apple安全标题。请参阅更新的帖子。@sundance由于错误代码而被否决,数据中带有俄文符号,与导入相比给出了不同的结果CommonCrypto@Sergei投票被否决,请参阅我在中的评论