Ios 在swift中实现HMAC和SHA1加密
我对Swift比较陌生,我一直在使用HMAC和SHA1进行加密。我找到了下面的答案,但我不知道如何正确地实现它。任何帮助都将是惊人的。我使用了这个模块,我将它作为一个框架添加到我的项目中: 我还为SHA256.swift添加了以下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(
字符串扩展名:
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投票被否决,请参阅我在中的评论