web-dev-qa-db-fra.com

Comment hacher NSString avec SHA1 dans Swift?

Dans objectif-c, cela ressemble à ceci:

#include <sys/xattr.h>

@implementation NSString (reverse)

-(NSString*)sha1
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, (int)data.length, digest);
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", digest[i]];
    return output;
}

@end

J'ai besoin de quelque chose comme ça avec Swift, est-ce possible?

S'il vous plaît, montrez l'exemple de travail.

39
imike

Votre code Objective-C (en utilisant une catégorie NSString) peut être traduit directement en Swift (En utilisant une extension String).

Vous devez d’abord créer un "en-tête de pontage" et ajouter

#import <CommonCrypto/CommonCrypto.h>

Ensuite:

extension String {
    func sha1() -> String {
        let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
        var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
        CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
        let output = NSMutableString(capacity: Int(CC_SHA1_DIGEST_LENGTH))
        for byte in digest {
            output.appendFormat("%02x", byte)
        }
        return output as String
    }
}

println("Hello World".sha1())

Cela peut être écrit légèrement plus court et Swifter comme

extension String {
    func sha1() -> String {
        let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
        var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
        CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
        let hexBytes = map(digest) { String(format: "%02hhx", $0) }
        return "".join(hexBytes)
    }
}

Mise à jour pour Swift 2:

extension String {
    func sha1() -> String {
        let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
        var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
        CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joinWithSeparator("")
    }
}

Pour renvoyer une chaîne encodée en Base 64 au lieu d'une chaîne encodée en hexadécimal, remplacez 

        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joinWithSeparator("")

avec

        return NSData(bytes: digest, length: digest.count).base64EncodedStringWithOptions([])

Mise à jour pour Swift 3:

extension String {
    func sha1() -> String {
        let data = self.data(using: String.Encoding.utf8)!
        var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
        data.withUnsafeBytes { 
            _ = CC_SHA1($0, CC_LONG(data.count), &digest)
        }
        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joined()
    }
}

Pour renvoyer une chaîne encodée en Base 64 au lieu d'une chaîne encodée en hexadécimal, remplacez 

        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joined()

par 

        return Data(bytes: digest).base64EncodedString()
121
Martin R

Pour obtenir le résultat sous la forme NSData, à condition que vous ayez inclus <CommonCrypto/CommonCrypto.h> dans votre en-tête de pontage:

extension NSData {

    func sha1() -> NSData? {
        let len = Int(CC_SHA1_DIGEST_LENGTH)
        let digest = UnsafeMutablePointer<UInt8>.alloc(len)
        CC_SHA1(bytes, CC_LONG(length), digest)
        return NSData(bytesNoCopy: UnsafeMutablePointer<Void>(digest), length: len)
    }
}

Utilise également une allocation de pointeur appropriée. Invoquez-le comme ceci:

myString.dataUsingEncoding(NSUTF8StringEncoding)?.sha1()

Si vous avez besoin d'une représentation hexadécimale de NSData, jetez un œil à mon autre réponse .

4
Erik Aigner

Oui, c'est possible, copiez cette classe dans votre projet . https://github.com/idrougge/sha1-Swift

Et ce sera facile comme:

 SHA1.hexString(from: "myPhrase" )!

Testé pour Swift 3 et Swift 4.

4
MrMins

Nous pouvons extraire la logique de chiffrement de chaîne en utilisant sha1 pour trois étapes:

  1. Convertir une chaîne en objet de données
  2. Chiffrer les données à l'aide de la fonction SHA1 en données
  3. Convertir un objet de données en chaîne hexagonale

IMHO c'est beaucoup plus lisible et cette version ne nécessite pas NSData.

    extension String {

        var sha1: String {
            guard let data = data(using: .utf8, allowLossyConversion: false) else {
                // Here you can just return empty string or execute fatalError with some description that this specific string can not be converted to data
            }
            return data.digestSHA1.hexString
        }

    }

    fileprivate extension Data {

        var digestSHA1: Data {
            var bytes: [UInt8] = Array(repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))

            withUnsafeBytes {
                _ = CC_SHA1($0, CC_LONG(count), &bytes)
            }

            return Data(bytes: bytes)
        }

        var hexString: String {
            return map { String(format: "%02x", UInt8($0)) }.joined()
        }

    }
1
Mateusz Szklarek

Oui, c'est possible: rendre ce code objective-c accessible depuis Swift

Voir documentation

J'éviterais de la réécrire dans Swift si vous n'obtenez aucun avantage (comme l'utilisation de fonctionnalités spécifiques à Swift).

De plus, dans un projet sur lequel je travaille, j'ai utilisé un code objective-c similaire au vôtre pour gérer les hachages. Au début, j’ai commencé à l’écrire dans Swift, puis j’ai réalisé qu’il était tout simplement plus facile et meilleur de réutiliser le vieil obj-c.

0
Antonio