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.
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
- (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;
}
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
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 :)
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];
}
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
Je vois quelques améliorations possibles aux réponses dans cet article.
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