5

我正在尝试实现一个系统,其中 A 生成一个 RSA 密钥对并将公钥发送给 B。B 然后生成一个 AES 密钥并使用公钥对其进行加密,将结果发送回 A。A 然后解密 AES 密钥使用其 RSA 私钥,使用 AES 密钥加密数据并将其发送给 B,然后 B 可以使用 AES 密钥对其进行解密。

我已经在 Android 端完成了这一切,但我无法让 iPhone 端玩球(我是 Objective C 的新手,所以这可能就是原因!)

最初,我在使用 RSA 私钥解密 AES 密钥时收到错误 9809,这无济于事地转化为一般错误。研究错误指向填充(我正在使用 PKCS1 填充)是问题,切换到无填充允许 iPhone 客户端成功解密,但解密的 AES 密钥与 Android 客户端上生成的不同。

Objective C对我来说很新,我确定我只是犯了一个小学生的错误,有人能指出我正确的方向吗?

iPhone RSA 密钥对生成

static const unsigned char _encodedRSAEncryptionOID[15] = {

    /* Sequence of length 0xd made up of OID followed by NULL */
    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
    0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00

};

NSData * publicTag = [publicKeyIdentifier dataUsingEncoding:NSUTF8StringEncoding];

// Now lets extract the public key - build query to get bits
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];

[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) kSecReturnData];

CFTypeRef pk;
OSStatus err = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, &pk);

NSData* publicKeyBits = (__bridge_transfer NSData*)pk;

if (err != noErr) {
    return nil;
}

// OK - that gives us the "BITSTRING component of a full DER
// encoded RSA public key - we now need to build the rest

unsigned char builder[15];
NSMutableData * encKey = [[NSMutableData alloc] init];
int bitstringEncLength;

// When we get to the bitstring - how will we encode it?
if  ([publicKeyBits length ] + 1  < 128 )
    bitstringEncLength = 1 ;
else
    bitstringEncLength = (([publicKeyBits length ] +1 ) / 256 ) + 2 ;

// Overall we have a sequence of a certain length
builder[0] = 0x30;    // ASN.1 encoding representing a SEQUENCE
// Build up overall size made up of -
// size of OID + size of bitstring encoding + size of actual key
size_t i = sizeof(_encodedRSAEncryptionOID) + 2 + bitstringEncLength +
[publicKeyBits length];
size_t j = encodeLength(&builder[1], i);
[encKey appendBytes:builder length:j +1];

// First part of the sequence is the OID
[encKey appendBytes:_encodedRSAEncryptionOID
             length:sizeof(_encodedRSAEncryptionOID)];

// Now add the bitstring
builder[0] = 0x03;
j = encodeLength(&builder[1], [publicKeyBits length] + 1);
builder[j+1] = 0x00;
[encKey appendBytes:builder length:j + 2];

// Now the actual key
[encKey appendData:publicKeyBits];

// Now translate the result to a Base64 string
Base64* base64 = [[Base64 alloc] init];
NSString* ret = [base64 encode:encKey];

return ret;

重新创建公钥,生成 AES 密钥并在 Android 上对其进行加密 (注意getBytes(...)getString(...)只需执行一些 base64 编码。解码)

KeyGenerator keyGen  = KeyGenerator.getInstance("AES");
keyGen.init(256, new SecureRandom());
SecretKey secretKey = keyGen.generateKey();

byte[] publicKeyBytes = getBytes(publicKey.getKey());
PublicKey rsaKey = KeyFactory.getInstance("RSA")
    .generatePublic(new X509EncodedKeySpec(publicKeyBytes));

Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE, rsaKey);

String keyEncoded = getString(key);

return getString(encryptedKeyBytes));

解密 iPhone 上的 AES 密钥

Base64* base64 = [[Base64 alloc] init];
NSData* cipherText = [base64 decode:textBase64];

const uint8_t *cipherBuffer = (const uint8_t*)[cipherText bytes];

size_t cipherBufferSize = strlen((char *) cipherBuffer);

uint8_t *plainBuffer = (uint8_t *)calloc(SecKeyGetBlockSize(publicKey), sizeof(uint8_t));
size_t plainBufferSize = SecKeyGetBlockSize(publicKey);

OSStatus status = SecKeyDecrypt(privateKey,
                       kSecPaddingPKCS1,
                       &cipherBuffer[0],
                       cipherBufferSize,
                       &plainBuffer[0],
                       &plainBufferSize
                       );

NSData* finalData = [[NSData alloc] initWithBytes:plainBuffer length:plainBufferSize];
NSString *result = [base64 encode:finalData];

return result;

编辑:我想我已经缩小了这个范围,下面的代码来自我的代码的解密 AES 密钥部分:

NSData* cipherText = [base64 decode:text];
NSLog(@"cipherText %@", cipherText);
const uint8_t *cipherBuffer = (const uint8_t*)[cipherText bytes];
NSLog(@"cipherBuffer %s", cipherBuffer);

size_t cipherBufferSize = strlen((char *) cipherBuffer);
NSLog(@"cipherBufferSize %zd", cipherBufferSize);

在控制台中产生以下输出:

cipherText <31226275 cc56069a e96b7f6f 0fbee853 32d07de6 436755c9 e27b88a6 04176947     d57f7108 de68e5b8 49595e9f 09bceb30 1d615927 c205f205 eb644fa7 bff6c02b 885605de eb5bd4ee 473bb4d3 df768017 24552706 ea67f347 2952614e ad63f3c6 eb0022d3 a0513afa 0e59ba63 cb5c9787 a40ecad4 a866fdc7 26b60cc2 088a3499 a84c0595 fb1c2be8 5c85b88d 7856b4bd 655f6fec 905ca221 d6bb03c0 7329410b b235ef8f 1ef97a64 7fabb280 90118ff7 4b1e91f6 162134fc 5cbf962e 813e39e7 993b0fb9 e3c4b30c ef6a7b90 9d64c41a 1211ab34 c2c52235 d2ec3b65 d1314cee 70eafe65 f4a6c5e4 660cf889 4540a784 d14cc5a8 49a12c43 c76f7f03 5fbcd44f>
cipherBuffer 1"buÃVöÈkoæËS2–}ÊCgU…‚{à¶iG’qfihÂ∏IY^ü  ºÎ0aY'¬ÚÎdOßøˆ¿+àVfiÎ[‘ÓG;¥”flvÄ$U'ÍgÛG)RaN≠cÛ∆Î
cipherBufferSize 97

然而,有时它会按预期输出 256 的密码缓冲区大小,并且解密效果很好!我知道我一定遗漏了一些明显的东西?

4

1 回答 1

0

您的问题在于该strlen函数,该函数通常不适用于二进制数据,它仅适用于表示文本的二进制数据,并且以零值字节 ( \0) 结束。相反,您应该使用密文的实际大小。

因此,如果密文包含零值字节,或者如果密文后面没有直接跟随零值字节,那么目前您的代码块将失败。

于 2013-06-17T11:45:30.020 回答