[swift] 신속한 SHA256

내 프로젝트에서 sha256을 사용하고 싶지만 objC 코드를 신속한 코드로 다시 작성하는 데 몇 가지 문제가있었습니다. 도와주세요, 제발. 이 답변을 사용했습니다. iOS에서 SHA-2 (이상적으로 SHA 256 또는 SHA 512) 해시를 계산하려면 어떻게해야합니까?

내 코드는 다음과 같습니다.

var hash : [CUnsignedChar]
CC_SHA256(data.bytes, data.length, hash)
var res : NSData = NSData.dataWithBytes(hash, length: CC_SHA256_DIGEST_LENGTH)

빠른 변환 할 수 없기 때문에 그것은 나에게 오류 모든 것을 제공 IntCC_LONG예를 들어,.



답변

Swift는 (Objective-) C 에서처럼 암시 적 변환을하지 않기 때문에 Int와 사이에서 명시 적으로 변환해야합니다 CC_LONG.

또한 hash필요한 크기의 배열 로 정의 해야합니다.

func sha256(data : NSData) -> NSData {
    var hash = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0)
    CC_SHA256(data.bytes, CC_LONG(data.length), &hash)
    let res = NSData(bytes: hash, length: Int(CC_SHA256_DIGEST_LENGTH))
    return res
}

또는를 사용 NSMutableData하여 필요한 버퍼를 할당 할 수 있습니다 .

func sha256(data : NSData) -> NSData {
    let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH))
    CC_SHA256(data.bytes, CC_LONG(data.length), UnsafeMutablePointer(res.mutableBytes))
    return res
}

Swift 3 및 4 업데이트 :

func sha256(data : Data) -> Data {
    var hash = [UInt8](repeating: 0,  count: Int(CC_SHA256_DIGEST_LENGTH))
    data.withUnsafeBytes {
        _ = CC_SHA256($0, CC_LONG(data.count), &hash)
    }
    return Data(bytes: hash)
}

Swift 5 업데이트 :

func sha256(data : Data) -> Data {
    var hash = [UInt8](repeating: 0,  count: Int(CC_SHA256_DIGEST_LENGTH))
    data.withUnsafeBytes {
        _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
    }
    return Data(hash)
}


답변

최고의 답변이 저에게 효과가 없었습니다. 나는 웹에서 무언가를 발견하고 그것을 약간 변경했고 이제 작동합니다 : D. Swift 3 및 4 용입니다.

이 확장을 프로젝트 어딘가에 놓고 다음과 같은 문자열에 사용하십시오. mystring.sha256 ()

extension String {

    func sha256() -> String {
        if let stringData = self.data(using: String.Encoding.utf8) {
            return hexStringFromData(input: digest(input: stringData as NSData))
        }
        return ""
    }

    private func digest(input : NSData) -> NSData {
        let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
        var hash = [UInt8](repeating: 0, count: digestLength)
        CC_SHA256(input.bytes, UInt32(input.length), &hash)
        return NSData(bytes: hash, length: digestLength)
    }

    private 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
    }

}

그런데 CommonCrypto를 가져 오는 브리징 헤더가 필요합니다. 계정이없는 경우 다음 단계를 따르세요.

  1. 새 파일 만들기-> 헤더 파일-> 다른 이름으로 저장 BridgingHeader
  2. 빌드 설정-> Objective-C 브리징 헤더-> 추가 ProjectName/BridgingHeader.h
  3. #import <CommonCrypto/CommonHMAC.h>헤더 파일에 넣기


답변

함께 CryptoKitiOS13 추가, 우리는 이제 기본 스위프트의 API를 가지고 :

import Foundation
import CryptoKit

// CryptoKit.Digest utils
extension Digest {
    var bytes: [UInt8] { Array(makeIterator()) }
    var data: Data { Data(bytes) }

    var hexStr: String {
        bytes.map { String(format: "%02X", $0) }.joined()
    }
}

func example() {
    guard let data = "hello world".data(using: .utf8) else { return }
    let digest = SHA256.hash(data: data)
    print(digest.data) // 32 bytes
    print(digest.hexStr) // B94D27B9934D3E08A52E52D7DA7DABFAC484EFE37A5380EE9088F7ACE2EFCDE9
}

유틸이 프로토콜에 정의되어 있기 때문에 Digest모든 입력을 소화을 위해, 당신이 그것을 사용할 수 있습니다 CryptoKit, 같은 SHA384Digest, SHA512Digest, SHA1Digest, MD5Digest


답변

NSData& String(Swift 3) 에서 SHA를 제공하는 함수 :

func sha256(_ data: Data) -> Data? {
    guard let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH)) else { return nil }
    CC_SHA256((data as NSData).bytes, CC_LONG(data.count), res.mutableBytes.assumingMemoryBound(to: UInt8.self))
    return res as Data
}

func sha256(_ str: String) -> String? {
    guard
        let data = str.data(using: String.Encoding.utf8),
        let shaData = sha256(data)
        else { return nil }
    let rc = shaData.base64EncodedString(options: [])
    return rc
}

브리징 헤더에 포함 :

#import "CommonCrypto/CommonCrypto.h"


답변

iOS 13에서 CryptoKit을 사용하고 그렇지 않으면 CommonCrypto로 대체하는 Swift 5 용 버전 :

import CommonCrypto
import CryptoKit
import Foundation

private func hexString(_ iterator: Array<UInt8>.Iterator) -> String {
    return iterator.map { String(format: "%02x", $0) }.joined()
}

extension Data {

    public var sha256: String {
        if #available(iOS 13.0, *) {
            return hexString(SHA256.hash(data: self).makeIterator())
        } else {
            var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
            self.withUnsafeBytes { bytes in
                _ = CC_SHA256(bytes.baseAddress, CC_LONG(self.count), &digest)
            }
            return hexString(digest.makeIterator())
        }
    }

}

용법:

let string = "The quick brown fox jumps over the lazy dog"
let hexDigest = string.data(using: .ascii)!.sha256
assert(hexDigest == "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592")

Swift 패키지 관리자를 통해서도 사용 가능 :
https://github.com/ralfebert/TinyHashes


답변

import CommonCrypto

public extension String {

  var sha256: String {
      let data = Data(utf8)
      var hash = [UInt8](repeating: 0,  count: Int(CC_SHA256_DIGEST_LENGTH))

      data.withUnsafeBytes { buffer in
          _ = CC_SHA256(buffer.baseAddress, CC_LONG(buffer.count), &hash)
      }

      return hash.map { String(format: "%02hhx", $0) }.joined()
  }
}


답변

다음은 macOS 기반 Foundation의 일부인 Security Transforms API를 사용하는 간단한 3 줄 Swift 4 함수입니다. (안타깝게도 iOS 프로그래머는이 기술을 사용할 수 없습니다.)

import Foundation

extension Data {
    public func sha256Hash() -> Data {
        let transform = SecDigestTransformCreate(kSecDigestSHA2, 256, nil)
        SecTransformSetAttribute(transform, kSecTransformInputAttributeName, self as CFTypeRef, nil)
        return SecTransformExecute(transform, nil) as! Data
    }
}