Ich empfange Daten, die mit SJCL verschlüsselt wurden, in eine iOS-App, wo ich sie entschlüsseln muss. Das andere Ende verwendet SJCL mit dem AES CCM-Modus, der nicht von Apples CommonCrypto unterstützt wird, also verwende ich die VPCCMCrypt-Bibliothek dafür. Änderungen an der anderen Seite, die den SJCL-Chiffretext sendet, sind nicht möglich.Entschlüsseln von SJCL-Chiffretext in Objective-C
Hier sind meine Methoden zu entschlüsseln:
+ (NSData *)decryptSjcl:(NSDictionary *)cipher password:(NSString *)password {
if (cipher == nil || password == nil) {
return nil;
}
int version = [cipher[@"v"] intValue];
NSString *iv = cipher[@"iv"];
uint iter = [cipher[@"iter"] unsignedIntValue];
uint ks = [cipher[@"ks"] unsignedIntValue];
uint ts = [cipher[@"ts"] unsignedIntValue];
NSString *mode = cipher[@"mode"];
NSString *adata = cipher[@"adata"];
NSString *algorithm = cipher[@"cipher"];
NSString *salt = cipher[@"salt"];
NSString *ct = cipher[@"ct"];
if (version != 1 || ! [@"aes" isEqualToString:algorithm]) {
return nil;
}
NSData *rawIv = [[NSData alloc] initWithBase64EncodedString:iv options:0];
NSData *rawSalt = [[NSData alloc] initWithBase64EncodedString:salt options:0];
NSData *rawAdata = [[NSData alloc] initWithBase64EncodedString:adata options:0];
NSData *cipherData = [[NSData alloc] initWithBase64EncodedString:ct options:0];
NSData *key;
NSMutableData *decipheredData = nil;
if ([@"ccm" isEqualToString:mode]) {
key = [Cryptor sjclAesKeyForPassword:password salt:rawSalt iterations:iter keySize:ks];
decipheredData = [Cryptor decryptAesCcmData:cipherData iv:rawIv key:key adata:rawAdata tagSize:ts];
}
return decipheredData;
}
SJCL Schlüsselerzeugung:
+ (NSData *)sjclAesKeyForPassword:(NSString *)password salt:(NSData *)salt iterations:(uint)iterations keySize:(uint)keySizeBits {
NSMutableData *derivedKey = [NSMutableData dataWithLength:keySizeBits/8];
int result = CCKeyDerivationPBKDF(kCCPBKDF2,
password.UTF8String,
[password lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
salt.bytes,
salt.length,
kCCPRFHmacAlgSHA256,
iterations,
derivedKey.mutableBytes,
derivedKey.length);
NSAssert(result == kCCSuccess, @"Unable to create AES key for password: %d", result);
return derivedKey;
}
AES CCM Entschlüsselung:
+ (NSMutableData *)decryptAesCcmData:(NSData *)cipherData iv:(NSData *)iv key:(NSData *)key adata:(NSData *)adata tagSize:(uint)tagSizeBits {
VPCCMCrypt *ccm = [[VPCCMCrypt alloc] initWithKey:key
iv:iv
adata:adata
tagLength:tagSizeBits/8];
[ccm decryptDataWithData:cipherData
finishedBlock:^(NSData *data) {
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Decrypted SJCL message: %@", result);
}
errorBlock:^(NSError *error) {
NSLog(@"ERROR");
}];
return nil;
}
Alle Eingabedaten aus dem SJCL korrekt analysiert (IV, Salz, Schlüsselgröße, Tag-Größe, PBKDF-Iterationen, Chiffretext) und zu NSData
her m ihre Base64
kodierte Darstellung. Passwort wird gleich verwendet. Alle Daten einschließlich des erstellten AES-Schlüssels sind nicht Null.
Am Ende schlägt es innerhalb der VPCCMCrypt
Überprüfung der CCM-Tag (Tags sind unterschiedlich). Ist etwas falsch mit dem obigen Code? Gibt es eine andere iOS/Objective-C/Swift-Bibliothek, um AES CCM oder noch besser die SJCL zu entschlüsseln? Ich bin nicht an einem JavaScript-Wrapper der SJCL-Bibliothek interessiert.
Zum Testen verwende ich einfache verschlüsselte Daten von SJCL's demo page.
EDIT:
Wie gesagt in den Kommentaren SJCL IV 16 Byte senden anstelle von maximal 12 Bytes für den CCM-Modus und dann intern klemmt es maximal 12 Bytes, wenn entziffern. Hier ist die aktualisierte Entschlüsselungsmethode:
+ (NSData *)decryptSjcl:(NSDictionary *)cipher password:(NSString *)password {
if (cipher == nil || password == nil) {
return nil;
}
int version = [cipher[@"v"] intValue];
NSString *iv = cipher[@"iv"];
uint iter = [cipher[@"iter"] unsignedIntValue];
uint ks = [cipher[@"ks"] unsignedIntValue];
uint ts = [cipher[@"ts"] unsignedIntValue];
NSString *mode = cipher[@"mode"];
NSString *adata = cipher[@"adata"];
NSString *algorithm = cipher[@"cipher"];
NSString *salt = cipher[@"salt"];
NSString *ct = cipher[@"ct"];
if (version != 1 || ! [@"aes" isEqualToString:algorithm]) {
return nil;
}
NSMutableData *rawIv = [[NSMutableData alloc] initWithBase64EncodedString:iv options:0];
NSMutableData *rawSalt = [[NSMutableData alloc] initWithBase64EncodedString:salt options:0];
NSMutableData *rawAdata = [[NSMutableData alloc] initWithBase64EncodedString:adata options:0];
NSMutableData *cipherData = [[NSMutableData alloc] initWithBase64EncodedString:ct options:0];
NSData *key;
NSData *decipheredData = nil;
if ([@"ccm" isEqualToString:mode]) {
key = [Cryptor sjclAesKeyForPassword:password salt:rawSalt iterations:iter keySize:ks];
// Clamp the SJCL IV - They use a 16 byte IV for CCM mode which is against specification and they do a funky
// clamping. CCM mode IV should be max 13 bytes long. They almost always clamp it to 13 bytes but save the whole
// 16 bytes in their JSON container.
// for (L=2; L<4 && ol >>> 8*L; L++) {}
// if (L < 15 - ivl) { L = 15-ivl; }
// iv = w.clamp(iv,8*(15-L));
int64_t ivl = rawIv.length;
int64_t ol = cipherData.length - (ts/8);
int64_t L = 2;
for (L = 2; L < 4 && ol >> 8*L; L++) {}
if (L < 15 - ivl) {
L = 15 - ivl;
}
NSRange subrange = NSMakeRange(0, (NSUInteger)(15 - L));
decipheredData = [Cryptor decryptAesCcmData:cipherData iv:[rawIv subdataWithRange:subrange] key:key adata:rawAdata tagSize:ts];
}
else {
decipheredData = nil;
}
return decipheredData;
}
Eine letzte fehlende Sache der TAG ist die Überprüfung, ich bin nicht in der Lage, das zu tun. Irgendwelche Ideen?
Vielen Dank, aber ich habe bereits diesen Teil der Probleme gelöst und haben die IV Klemm in meinem Code hinzugefügt. Ich hatte jedoch nicht die Zeit, meine Frage zu aktualisieren, und niemand kümmerte sich auch darum. Ich werde das Objective-C später hinzufügen. Bei der geklemmten IV funktioniert die Entschlüsselung aber die TAG-Verifikation schlägt immer noch fehl. Irgendeine Idee, warum die TAG-Verifikation auch bei richtig eingespannter IV fehlschlägt? Tut die SJCL etwas Funky mit der TAG wie mit der IV, die gegen die Spezifikation ist? – shelll
Ich habe gerade meine Frage mit dem aktualisierten Objective-C-Code aktualisiert, um die IV auf maximal 12 Bytes zu begrenzen. Ich werde Ihre Antwort akzeptieren, da die Entschlüsselung funktioniert, aber der TAG noch immer nicht verifiziert ist. – shelll
Das VPCCMCrypt decryptDataWithData überprüft das Tag. Wenn das Dekodieren funktioniert, wird das Tag verifiziert! https://github.com/billp/VPCCMCrypt/blob/master/lib/VPCCMCrypt.m#L308 – soyer