How can I use a PKCS8 RSA DER Private Key in iOS?

后端 未结 2 1660
忘掉有多难
忘掉有多难 2021-01-14 10:46

At run time, my iOS application receives a file with a public-private RSA key-pair, generated by someone else\'s Java:

KeyPairGenerator keygenerator;
keygene         


        
相关标签:
2条回答
  • 2021-01-14 11:02

    I couldn't solve the problem without OpenSSL. So here is a solution that does use OpenSSL.

    Assuming you have a NSData called privateKey with the key, and another called signableData which you want to sign.

    #import <openssl/x509.h>
    #import <openssl/pem.h>
    
    NSURL *cacheDir = [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
    NSString *infile = [[cacheDir URLByAppendingPathComponent:@"privkey.der"] path];
    
    NSError *error;
    [privateKey writeToFile:infile options:NSDataWritingFileProtectionComplete error:&error];
    if (error) {
        NSLog(@"%@", error);
    } else {
        BIO *in = BIO_new_file([infile cStringUsingEncoding:NSUTF8StringEncoding], "rb");
        PKCS8_PRIV_KEY_INFO *p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL);
        NSLog(@"%i", p8inf->broken);
        EVP_PKEY *pkey = EVP_PKCS82PKEY(p8inf);
        PKCS8_PRIV_KEY_INFO_free(p8inf);
        BIO_free(in);
    
        uint8_t * cipherBuffer = NULL;
    
        // Calculate the buffer sizes.
        unsigned int cipherBufferSize = RSA_size(pkey->pkey.rsa);
        unsigned int signatureLength;
    
        // Allocate some buffer space. I don't trust calloc.
        cipherBuffer = malloc(cipherBufferSize);
        memset((void *)cipherBuffer, 0x0, cipherBufferSize);
    
        unsigned char *openSSLHash = SHA1(signableData.bytes, signableData.length, NULL);
        int success = RSA_sign(NID_sha1, openSSLHash, 20, cipherBuffer, &signatureLength, pkey->pkey.rsa);
        if (success) NSLog(@"WIN");
    
    
        NSData *signed = [NSData dataWithBytes:(const void*)cipherBuffer length:signatureLength];    
    
        EVP_PKEY_free(pkey);
    }
    
    0 讨论(0)
  • 2021-01-14 11:08

    You can see how a der key looks in ASN1 structure in this webpage: https://lapo.it/asn1js/

    Here is a code from the SwCrypt library, which strips the PKCS8 header from a private key. This is Swift, but you can rewrite it any other language easily.

        static private func stripHeaderIfAny(keyData: NSData) throws -> NSData {
            var bytes = keyData.arrayOfBytes()
    
            var offset = 0
            guard bytes[offset] == 0x30 else {
                throw SwError.ASN1Parse
            }
            offset += 1
    
            if bytes[offset] > 0x80 {
                offset += Int(bytes[offset]) - 0x80
            }
            offset += 1
    
            guard bytes[offset] == 0x02 else {
                throw SwError.ASN1Parse
            }
            offset += 3
    
            //without PKCS8 header
            if bytes[offset] == 0x02 {
                return keyData
            }
    
            let OID: [UInt8] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
                                0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00]
            let slice: [UInt8] = Array(bytes[offset..<(offset + OID.count)])
    
            guard slice == OID else {
                throw SwError.ASN1Parse
            }
    
            offset += OID.count
            guard bytes[offset] == 0x04 else {
                throw SwError.ASN1Parse
            }
    
            offset += 1
            if bytes[offset] > 0x80 {
                offset += Int(bytes[offset]) - 0x80
            }
            offset += 1
    
            guard bytes[offset] == 0x30 else {
                throw SwError.ASN1Parse
            }
    
            return keyData.subdataWithRange(NSRange(location: offset, length: keyData.length - offset))
        }
    
    0 讨论(0)
提交回复
热议问题