0

我正在尝试实现 RSA 算法,我遵循了苹果参考。但是我遇到了将 uint8_t 转换为 NSData 到 NSString 的问题。

到目前为止我已经这样做了..这些函数在参考中定义

-(void)test{
    [self generateKeyPairPlease];
    NSData *data = [self encryptWithPublicKey]; //All goes well until here
    [self decryptWithPrivateKey:data]; 

}

对于加密我做了..

- (NSData *)encryptWithPublicKey
{
    OSStatus status = noErr;

    size_t cipherBufferSize;
    uint8_t *cipherBuffer;                     // 1

// [cipherBufferSize]
    const uint8_t dataToEncrypt[] = "the quick brown fox jumps "
                            "over the lazy dog\0"; // 2
    size_t dataLength = sizeof(dataToEncrypt)/sizeof(dataToEncrypt[0]);

    SecKeyRef publicKey = NULL;                                 // 3

    NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
             length:strlen((const char *)publicKeyIdentifier)]; // 4

    NSMutableDictionary *queryPublicKey =
                            [[NSMutableDictionary alloc] init]; // 5

    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
                                                                // 6

    status = SecItemCopyMatching
    ((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey); // 7

//  Allocate a buffer

    cipherBufferSize = SecKeyGetBlockSize(publicKey);
    cipherBuffer = malloc(cipherBufferSize);

//  Error handling

    if (cipherBufferSize < sizeof(dataToEncrypt)) {
        // Ordinarily, you would split the data up into blocks
        // equal to cipherBufferSize, with the last block being
        // shorter. For simplicity, this example assumes that
        // the data is short enough to fit.
        printf("Could not decrypt.  Packet too large.\n");
        return NULL;
    }

    // Encrypt using the public.
    status = SecKeyEncrypt(    publicKey,
                                kSecPaddingPKCS1,
                                dataToEncrypt,
                                (size_t) dataLength,
                                cipherBuffer,
                                &cipherBufferSize
                                );                              // 8

//  Error handling
//  Store or transmit the encrypted text

    if (publicKey) CFRelease(publicKey);

    NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];

    free(cipherBuffer);

    return encryptedData;
}

但是在decryptWithPrivateKey我无法将 uint8_t *plainBuffer(解密结果)转换为NSString.First 时,我尝试将其转换为NSData打印时NSLog正确显示字节,但随后NSData未转换为字符串。

- (void)decryptWithPrivateKey: (NSData *)dataToDecrypt
{
    OSStatus status = noErr;

    size_t cipherBufferSize = [dataToDecrypt length];
    uint8_t *cipherBuffer = (uint8_t *)[dataToDecrypt bytes];

    size_t plainBufferSize;
    uint8_t *plainBuffer;

    SecKeyRef privateKey = NULL;

    NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
                                         length:strlen((const char *)privateKeyIdentifier)];

    NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];

    // Set the private key query dictionary.
    [queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPrivateKey setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
    // 1

    status = SecItemCopyMatching
    ((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey); // 2

    //  Allocate the buffer
    plainBufferSize = SecKeyGetBlockSize(privateKey);
    plainBuffer = malloc(plainBufferSize);

    if (plainBufferSize < cipherBufferSize) {
        // Ordinarily, you would split the data up into blocks
        // equal to plainBufferSize, with the last block being
        // shorter. For simplicity, this example assumes that
        // the data is short enough to fit.
        printf("Could not decrypt.  Packet too large.\n");
        return;
    }

    //  Error handling

    status = SecKeyDecrypt(    privateKey,
                           kSecPaddingPKCS1,
                           cipherBuffer,
                           cipherBufferSize,
                           plainBuffer,
                           &plainBufferSize
                           );                              // 3

    //*******************************************************************************
    // Not able to convert  uint8_t *plainBuffer to string 
    // I also tried to convert it into NSData and then try to convert it into NSString but can't 
    //What Should i do here to get string back


  if(privateKey) CFRelease(privateKey);
}
@end

我想知道如何将解密结果转换uint8_t plainBufferNSDataNSString简单地NSString以便我得到我的字符串。有关我的加密和密钥生成代码,请参阅此参考

提前致谢..

4

3 回答 3

6

我知道这个问题很老,并且标记为已解决,但我遇到了类似的问题。我发现苹果文档中的加密方法似乎有错误

NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];

datalength 在这里是错误的变量。我用 cipherbuffersize 替换它

NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];

现在一切对我来说都很好。我希望它对我以外的其他人有用。

于 2013-03-19T14:29:19.327 回答
1

最可能的问题是您正在调用+[stringWithCharacters:length:]Unicode 字符(更准确地说是 UTF-16 代码点),但您可能使用 UTF-8 或其他 8 位编码。

您必须知道您拥有哪种编码,以便您可以调用+[stringWithCString:encoding:](或者,如果它是 UTF-8,+[stringWithUTF8String:]简称为 UTF-8)。

请注意,与 不同的是stringWithCharacters,这些方法不需要长度,并且期望您的数据以空值结尾。因此,除非您确定数据将始终具有终止符,否则您应该明确检查它,或者分配字符串然后调用-[initWithBytes:length:encoding:].

如果你不知道明文在加密之前是什么字符集,你需要找出来。作为人类,您通常可以通过查看它来判断,尤其是当它主要是 ASCII 时。使用缓冲区创建一个NSData并记录它并查看十六进制。如果是 UTF-16,ASCII 字符将与空值交替出现,'Hello'因此48 00 65 00 6C 00 6C 00 6F 00. 但是计算机并不能很好地进行猜测。(+[stringWithContentsOfFile:usedEncoding:error:]通常正确的原因是它查看了扩展属性com.apple.TextEncoding,大多数 Cocoa 应用程序在保存文件时都会写入该属性。)

于 2013-01-14T19:04:28.680 回答
0

我设法通过遵循这段 代码来解决我的问题。它是相同的代码,但字符串的编码是不同的。在encryptWithPublicKey我使用过的函数中

uint8_t *dataToEncrypt= (uint8_t *)[@"the quick brown fox jumps over the lazy dog" UTF8String];

代替

const uint8_t dataToEncrypt[] = "the quick brown fox jumps " "over the lazy dog\0";

decryptWithPrivateKey我用它来解码

 NSData *decryptedData = [NSData dataWithBytes:plainBuffer length:plainBufferSize];
 NSString *decryptedString = [[[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding] autorelease];
于 2013-01-16T19:37:36.580 回答