web-dev-qa-db-fra.com

Création d'un hachage SHA1 à partir de NSString

Comment créer un SHA1 à partir d'une NSString.

Disons que NSString est configuré comme suit:

NSString *message = @"Message";

Je peux utiliser PHP pour créer un hachage SHA1 avec sha($message). Mais malheureusement, cela ne fonctionne pas comme cela dans Objective-C.

42
Alex van Rijs

J'ai ceci dans une catégorie sur NSString (disponible sur https://github.com/hypercrypt/NSString-Hashes ):

#import <CommonCrypto/CommonDigest.h>

...

- (NSString *)sha1
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];

    CC_SHA1(data.bytes, (CC_LONG)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;
}

À partir de Xcode 10.0, vous devriez plutôt utiliser import CommonCrypto car il est maintenant disponible nativement dans Swift! Si vous avez récemment migré vers Xcode 10.0 et utilisez l'ancienne approche, cela peut être votre indice pour effectuer le changement:

La commande CompileSwift a échoué avec un code de sortie différent de zéro

88
hypercrypt

J'aime bien la réponse de hypercrypt, mais on m'a encouragé à poster mon commentaire.

Vous pouvez consulter CC_SHA1 , ou this related SO.

16
Alex
- (NSString *)sha1:(NSString *)str {
const char *cStr = [str UTF8String];
unsigned char result[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(cStr, strlen(cStr), result);
NSString *s = [NSString  stringWithFormat:
           @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
           result[0], result[1], result[2], result[3], result[4],
           result[5], result[6], result[7],
           result[8], result[9], result[10], result[11], result[12],
           result[13], result[14], result[15],
           result[16], result[17], result[18], result[19]
           ];

return s;
}
12
virata

J'aime tellement la réponse de hypercrypt que je l'ai emballée dans un petit dépôt git. Découvrez la catégorie NSString sur Github.

N'hésitez pas non plus à ajouter quelque chose de bon avec la cryptographie NSString

6
atreat

Il m'a fallu un certain temps pour porter la solution @hypercrypt sur Swift. J'ai donc décidé de la partager avec d'autres personnes susceptibles d'avoir le même problème. 

Une chose importante à noter est que vous avez besoin de la bibliothèque CommonCrypto, mais cette bibliothèque ne possède pas de module Swift. La solution de contournement la plus simple consiste à l'importer dans votre en-tête de pontage:

#import <CommonCrypto/CommonCrypto.h>

Une fois importé là-bas, vous n'avez besoin de rien d'autre. Il suffit d'utiliser l'extension String fournie:

extension String
{
    func sha1() -> String
    {
        var selfAsSha1 = ""

        if 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)

            for index in 0..<CC_SHA1_DIGEST_LENGTH
            {
                selfAsSha1 += String(format: "%02x", digest[Int(index)])
            }
        }

        return selfAsSha1
    }
}

Notez que ma solution ne prend pas en compte la réservation de la capacité de ce que NSMutableString a dans le message original. Cependant, je doute que quiconque voit la différence :)

4
hris.to

essaye ça:

#import <CommonCrypto/CommonDigest.h>

-(NSData *) selector
{
    unsigned char hashBytes[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1([dataToHash bytes], [dataToHash length], hashBytes);
    NSData *data = [[NSData alloc] initWithBytes:hashBytes length:CC_SHA1_DIGEST_LENGTH];
}
3
Saikrishna Rao

Voici une catégorie concise et hautement optimisée catégorie NSString :

@implementation NSString (PMUtils)
- (NSString *)sha1Hash
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    NSData *hash = [data sha1Hash];
    return [hash hexString];
} 
@end

@implementation NSData (PMUtils)
- (NSString *) hexString
{
    NSUInteger bytesCount = self.length;
    if (bytesCount) {
        static char const *kHexChars = "0123456789ABCDEF";
        const unsigned char *dataBuffer = self.bytes;
        char *chars = malloc(sizeof(char) * (bytesCount * 2 + 1));
        char *s = chars;
        for (unsigned i = 0; i < bytesCount; ++i) {
            *s++ = kHexChars[((*dataBuffer & 0xF0) >> 4)];
            *s++ = kHexChars[(*dataBuffer & 0x0F)];
            dataBuffer++;
        }
        *s = '\0';
        NSString *hexString = [NSString stringWithUTF8String:chars];
        free(chars);
        return hexString;
    }
    return @"";
}
- (NSData *)sha1Hash
{
    unsigned char digest[CC_SHA1_DIGEST_LENGTH];
    if (CC_SHA1(self.bytes, (CC_LONG)self.length, digest)) {
        return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
    }
    return nil;
}
@end
1
Peter

Je vois quelques améliorations possibles aux réponses dans cet article.

  1. Ne faites jamais une catégorie sans préfixe. Et si vous implémentiez - [NSString sha1Hash] dans votre bibliothèque et qu'une autre bibliothèque de la même application implémentait la même méthode avec une sémantique légèrement différente? Lequel utilisé sera aléatoire et conduira à des erreurs difficiles à diagnostiquer.
  2. Si vous voulez une chaîne, il existe de nos jours un encodage base64. Moins de travail que la construction manuelle d'une chaîne de caractères hexadécimale.

Voici ma solution, adaptée du SRHash.m : de l'excellente bibliothèque SocketRocket.

// NSString+Sha1Digest.h
#import <Foundation/Foundation.h>

@interface NSString (LBDigest)
- (NSString *)lb_digestString;
@end

@interface NSData (LBDigest)
- (NSString *)lb_digestString;
@end

// NSString+SHA1Digest.m
#import "NSString+Sha1Digest.h"
#import <CommonCrypto/CommonDigest.h>

static NSData *LBSHA1HashFromBytes(const char *bytes, size_t length)
{
    uint8_t outputLength = CC_SHA1_DIGEST_LENGTH;
    unsigned char output[outputLength];
    CC_SHA1(bytes, (CC_LONG)length, output);

    return [NSData dataWithBytes:output length:outputLength];
}

static NSData *LBSHA1HashFromString(NSString *string)
{
    size_t length = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    return LBSHA1HashFromBytes(string.UTF8String, length);
}

@implementation NSData (LBDigest)
- (NSString *)lb_digestString;
{
    return [LBSHA1HashFromBytes(self.bytes, self.length) base64EncodedStringWithOptions:0];
}
@end

@implementation NSString (LBDigest)
- (NSString *)lb_digestString;
{
    return [LBSHA1HashFromString(self) base64EncodedStringWithOptions:0];
}
@end
1
nevyn