Iphone - 如何使用公钥加密NSData并使用私钥解密?

时间:2012-04-09 10:49:29

标签: iphone nsdata encryption

我正在将UIImage转换为NSData。现在我需要使用公钥加密NSData,我需要使用私钥解密。请提供一步一步的程序。我需要使用哪种算法?有没有好的加密和解密库?还提供了一些用于加密和解密的代码段。

2 个答案:

答案 0 :(得分:19)

我已经尝试过 RSA加密和解密NSString ,您可以修改它并使其适用于 NSData

将Security.Framework添加到项目包中。

ViewController.h代码如下:

#import <UIKit/UIKit.h>
#import <Security/Security.h>

@interface ViewController : UIViewController
{
SecKeyRef publicKey;
SecKeyRef privateKey;
    NSData *publicTag;
    NSData *privateTag;
}
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer;
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer;
- (SecKeyRef)getPublicKeyRef;
- (SecKeyRef)getPrivateKeyRef;
- (void)testAsymmetricEncryptionAndDecryption;
- (void)generateKeyPair:(NSUInteger)keySize;
@end

ViewController.m文件代码如下:

#import "ViewController.h"

const size_t BUFFER_SIZE = 64;
const size_t CIPHER_BUFFER_SIZE = 1024;
const uint32_t PADDING = kSecPaddingNone;
static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey";

@implementation ViewController

-(SecKeyRef)getPublicKeyRef { 

    OSStatus sanityCheck = noErr; 
    SecKeyRef publicKeyReference = NULL;

    if (publicKeyReference == NULL) { 
        [self generateKeyPair:512];
                NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];

        // Set the public key query dictionary.
        [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];


        // Get the key.
        sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyReference);


        if (sanityCheck != noErr)
        {
            publicKeyReference = NULL;
        }


//        [queryPublicKey release];

    } else { publicKeyReference = publicKey; }

    return publicKeyReference; }

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}




- (void)testAsymmetricEncryptionAndDecryption {

    uint8_t *plainBuffer;
    uint8_t *cipherBuffer;
    uint8_t *decryptedBuffer;



    const char inputString[] = "How to Encrypt data with public key and Decrypt data with private key";
    int len = strlen(inputString);
    // TODO: this is a hack since i know inputString length will be less than BUFFER_SIZE
    if (len > BUFFER_SIZE) len = BUFFER_SIZE-1;

    plainBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t));
    cipherBuffer = (uint8_t *)calloc(CIPHER_BUFFER_SIZE, sizeof(uint8_t));
    decryptedBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t));

    strncpy( (char *)plainBuffer, inputString, len);

    NSLog(@"init() plainBuffer: %s", plainBuffer);
    //NSLog(@"init(): sizeof(plainBuffer): %d", sizeof(plainBuffer));
    [self encryptWithPublicKey:(UInt8 *)plainBuffer cipherBuffer:cipherBuffer];
    NSLog(@"encrypted data: %s", cipherBuffer);
    //NSLog(@"init(): sizeof(cipherBuffer): %d", sizeof(cipherBuffer));
    [self decryptWithPrivateKey:cipherBuffer plainBuffer:decryptedBuffer];
    NSLog(@"decrypted data: %s", decryptedBuffer);
    //NSLog(@"init(): sizeof(decryptedBuffer): %d", sizeof(decryptedBuffer));
    NSLog(@"====== /second test =======================================");

    free(plainBuffer);
    free(cipherBuffer);
    free(decryptedBuffer);
}

/* Borrowed from:
 * https://developer.apple.com/library/mac/#documentation/security/conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html
 */
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer
{

    NSLog(@"== encryptWithPublicKey()");

    OSStatus status = noErr;

    NSLog(@"** original plain text 0: %s", plainBuffer);

    size_t plainBufferSize = strlen((char *)plainBuffer);
    size_t cipherBufferSize = CIPHER_BUFFER_SIZE;

    NSLog(@"SecKeyGetBlockSize() public = %lu", SecKeyGetBlockSize([self getPublicKeyRef]));
    //  Error handling
    // Encrypt using the public.
    status = SecKeyEncrypt([self getPublicKeyRef],
                           PADDING,
                           plainBuffer,
                           plainBufferSize,
                           &cipherBuffer[0],
                           &cipherBufferSize
                           );
    NSLog(@"encryption result code: %ld (size: %lu)", status, cipherBufferSize);
    NSLog(@"encrypted text: %s", cipherBuffer);
}

- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer
{
    OSStatus status = noErr;

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

    NSLog(@"decryptWithPrivateKey: length of buffer: %lu", BUFFER_SIZE);
    NSLog(@"decryptWithPrivateKey: length of input: %lu", cipherBufferSize);

    // DECRYPTION
    size_t plainBufferSize = BUFFER_SIZE;

    //  Error handling
    status = SecKeyDecrypt([self getPrivateKeyRef],
                           PADDING,
                           &cipherBuffer[0],
                           cipherBufferSize,
                           &plainBuffer[0],
                           &plainBufferSize
                           );
    NSLog(@"decryption result code: %ld (size: %lu)", status, plainBufferSize);
    NSLog(@"FINAL decrypted text: %s", plainBuffer);

}



- (SecKeyRef)getPrivateKeyRef {
    OSStatus resultCode = noErr;
    SecKeyRef privateKeyReference = NULL;
//    NSData *privateTag = [NSData dataWithBytes:@"ABCD" length:strlen((const char *)@"ABCD")];
//    if(privateKey == NULL) {
        [self generateKeyPair:512];
        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];

        // Get the key.
        resultCode = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
        NSLog(@"getPrivateKey: result code: %ld", resultCode);

        if(resultCode != noErr)
        {
            privateKeyReference = NULL;
        }

//        [queryPrivateKey release];
//    } else {
//        privateKeyReference = privateKey;
//    }

    return privateKeyReference;
}


#pragma mark - View lifecycle



- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
    publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
    [self testAsymmetricEncryptionAndDecryption];

}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    } else {
        return YES;
    }
}

- (void)generateKeyPair:(NSUInteger)keySize {
    OSStatus sanityCheck = noErr;
    publicKey = NULL;
    privateKey = NULL;

//  LOGGING_FACILITY1( keySize == 512 || keySize == 1024 || keySize == 2048, @"%d is an invalid and unsupported key size.", keySize );

    // First delete current keys.
//  [self deleteAsymmetricKeys];

    // Container dictionaries.
    NSMutableDictionary * privateKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary * publicKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary * keyPairAttr = [[NSMutableDictionary alloc] init];

    // Set top level dictionary for the keypair.
    [keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits];

    // Set the private key dictionary.
    [privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
    [privateKeyAttr setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
    // See SecKey.h to set other flag values.

    // Set the public key dictionary.
    [publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
    [publicKeyAttr setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    // See SecKey.h to set other flag values.

    // Set attributes to top level dictionary.
    [keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
    [keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];

    // SecKeyGeneratePair returns the SecKeyRefs just for educational purposes.
    sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);
//  LOGGING_FACILITY( sanityCheck == noErr && publicKey != NULL && privateKey != NULL, @"Something really bad went wrong with generating the key pair." );
    if(sanityCheck == noErr  && publicKey != NULL && privateKey != NULL)
    {
        NSLog(@"Successful");
    }
//  [privateKeyAttr release];
//  [publicKeyAttr release];
//  [keyPairAttr release];
}


@end

如果您需要更多帮助,请与我联系。

希望这有帮助。

答案 1 :(得分:14)

<强>的NSData + AESCrypt.h

#import <Foundation/Foundation.h>

@interface NSData (AESCrypt)

- (NSData *)AES256EncryptWithKey:(NSString *)key;
- (NSData *)AES256DecryptWithKey:(NSString *)key;

+ (NSData *)dataWithBase64EncodedString:(NSString *)string;
- (id)initWithBase64EncodedString:(NSString *)string;

- (NSString *)base64Encoding;
- (NSString *)base64EncodingWithLineLength:(NSUInteger)lineLength;

- (BOOL)hasPrefixBytes:(const void *)prefix length:(NSUInteger)length;
- (BOOL)hasSuffixBytes:(const void *)suffix length:(NSUInteger)length;

<强>的NSData + AESCrypt.m

#import "NSData+AESCrypt.h"
#import <CommonCrypto/CommonCryptor.h>

static char encodingTable[64] = 
{
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
    'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
    'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
    'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};

@implementation NSData (AESCrypt)

- (NSData *)AES256EncryptWithKey:(NSString *)key{
  // 'key' should be 32 bytes for AES256, will be null-padded otherwise
  char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
  bzero( keyPtr, sizeof( keyPtr ) ); // fill with zeroes (for padding)

  // fetch key data
  [key getCString:keyPtr maxLength:sizeof( keyPtr ) encoding:NSUTF8StringEncoding];

  NSUInteger dataLength = [self length];

  //See the doc: For block ciphers, the output size will always be less than or 
  //equal to the input size plus the size of one block.
  //That's why we need to add the size of one block here
  size_t bufferSize = dataLength + kCCBlockSizeAES128;
  void *buffer = malloc( bufferSize );

  size_t numBytesEncrypted = 0;
  CCCryptorStatus cryptStatus = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                      keyPtr, kCCKeySizeAES256,
                                      NULL /* initialization vector (optional) */,
                                      [self bytes], dataLength, /* input */
                                      buffer, bufferSize, /* output */
                                      &numBytesEncrypted );
  if( cryptStatus == kCCSuccess )
  {
    //the returned NSData takes ownership of the buffer and will free it on deallocation
    return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
  }

  free( buffer ); //free the buffer
  return nil;
}

- (NSData *)AES256DecryptWithKey:(NSString *)key{

  // 'key' should be 32 bytes for AES256, will be null-padded otherwise
  char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
  bzero( keyPtr, sizeof( keyPtr ) ); // fill with zeroes (for padding)

  // fetch key data
  [key getCString:keyPtr maxLength:sizeof( keyPtr ) encoding:NSUTF8StringEncoding];

  NSUInteger dataLength = [self length];

  //See the doc: For block ciphers, the output size will always be less than or 
  //equal to the input size plus the size of one block.
  //That's why we need to add the size of one block here
  size_t bufferSize = dataLength + kCCBlockSizeAES128;
  void *buffer = malloc( bufferSize );

 size_t numBytesDecrypted = 0;
 CCCryptorStatus cryptStatus = CCCrypt( kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                      keyPtr, kCCKeySizeAES256,
                                      NULL /* initialization vector (optional) */,
                                      [self bytes], dataLength, /* input */
                                      buffer, bufferSize, /* output */
                                      &numBytesDecrypted );

  if( cryptStatus == kCCSuccess )
  {
    //the returned NSData takes ownership of the buffer and will free it on deallocation
    return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
  }

  free( buffer ); //free the buffer
  return nil;
}

#pragma mark -

+ (NSData *)dataWithBase64EncodedString:(NSString *)string
{
   return [[[NSData allocWithZone:nil] initWithBase64EncodedString:string] autorelease];
}

- (id)initWithBase64EncodedString:(NSString *)string
{
   NSMutableData *mutableData = nil;

   if( string )
   {
      unsigned long ixtext = 0;
      unsigned long lentext = 0;
      unsigned char ch = 0;
      unsigned char inbuf[4], outbuf[3];
      short i = 0, ixinbuf = 0;
      BOOL flignore = NO;
      BOOL flendtext = NO;
      NSData *base64Data = nil;
      const unsigned char *base64Bytes = nil;

      // Convert the string to ASCII data.
      base64Data = [string dataUsingEncoding:NSASCIIStringEncoding];
      base64Bytes = [base64Data bytes];
      mutableData = [NSMutableData dataWithCapacity:base64Data.length];
      lentext = base64Data.length;

      while( YES )
     {
         if( ixtext >= lentext ) break;
         ch = base64Bytes[ixtext++];
         flignore = NO;

         if( ( ch >= 'A' ) && ( ch <= 'Z' ) ) ch = ch - 'A';
         else if( ( ch >= 'a' ) && ( ch <= 'z' ) ) ch = ch - 'a' + 26;
         else if( ( ch >= '0' ) && ( ch <= '9' ) ) ch = ch - '0' + 52;
         else if( ch == '+' ) ch = 62;
         else if( ch == '=' ) flendtext = YES;
         else if( ch == '/' ) ch = 63;
         else flignore = YES;

         if( ! flignore )
         {
           short ctcharsinbuf = 3;
           BOOL flbreak = NO;

           if( flendtext ) 
           {
              if( ! ixinbuf ) break;
              if( ( ixinbuf == 1 ) || ( ixinbuf == 2 ) ) ctcharsinbuf = 1;
              else ctcharsinbuf = 2;
              ixinbuf = 3;
              flbreak = YES;
           }

            inbuf [ixinbuf++] = ch;

            if( ixinbuf == 4 ) 
           {
              ixinbuf = 0;
              outbuf [0] = ( inbuf[0] << 2 ) | ( ( inbuf[1] & 0x30) >> 4 );
              outbuf [1] = ( ( inbuf[1] & 0x0F ) << 4 ) | ( ( inbuf[2] & 0x3C ) >> 2 );
              outbuf [2] = ( ( inbuf[2] & 0x03 ) << 6 ) | ( inbuf[3] & 0x3F );

              for( i = 0; i < ctcharsinbuf; i++ )
                 [mutableData appendBytes:&outbuf[i] length:1];
           }

           if( flbreak )  break;
        }
     }
 }

  self = [self initWithData:mutableData];
  return self;
}

#pragma mark -

   - (NSString *)base64Encoding
   {
       return [self base64EncodingWithLineLength:0];
   }

   - (NSString *)base64EncodingWithLineLength:(NSUInteger)lineLength
   {
       const unsigned char   *bytes = [self bytes];
       NSMutableString *result = [NSMutableString stringWithCapacity:self.length];
       unsigned long ixtext = 0;
       unsigned long lentext = self.length;
       long ctremaining = 0;
       unsigned char inbuf[3], outbuf[4];
       unsigned short i = 0;
       unsigned short charsonline = 0, ctcopy = 0;
       unsigned long ix = 0;

       while( YES )
       {
           ctremaining = lentext - ixtext;
           if( ctremaining <= 0 ) break;

           for( i = 0; i < 3; i++ )
           {
               ix = ixtext + i;
               if( ix < lentext ) inbuf[i] = bytes[ix];
               else inbuf [i] = 0;
           }

           outbuf [0] = (inbuf [0] & 0xFC) >> 2;
           outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
           outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
           outbuf [3] = inbuf [2] & 0x3F;
           ctcopy = 4;

           switch( ctremaining )
           {
              case 1:
                 ctcopy = 2;
                 break;
              case 2:
                 ctcopy = 3;
                 break;
           }

          for( i = 0; i < ctcopy; i++ )
              [result appendFormat:@"%c", encodingTable[outbuf[i]]];

          for( i = ctcopy; i < 4; i++ )
              [result appendString:@"="];

          ixtext += 3;
          charsonline += 4;

          if( lineLength > 0 )
          {
             if( charsonline >= lineLength )
             {
                 charsonline = 0;
                 [result appendString:@"\n"];
             }
          }
     }

     return [NSString stringWithString:result];
  }
#pragma mark -
 - (BOOL)hasPrefixBytes:(const void *)prefix length:(NSUInteger)length
 {
     if( ! prefix || ! length || self.length < length ) return NO;
      return ( memcmp( [self bytes], prefix, length ) == 0 );
  }

  - (BOOL)hasSuffixBytes:(const void *)suffix length:(NSUInteger)length
  {
      if( ! suffix || ! length || self.length < length ) return NO;
       return ( memcmp( ((const char *)[self bytes] + (self.length - length)), suffix, length ) == 0  );
  }

您可以使用以下代码:

NSData *encryptedData = [UIImagePNGRepresentation(/*your image*/) AES256EncryptWithKey:/*your enc key*/];

NSData *plainData = [encryptedData AES256DecryptWithKey:/*your enc key*/];

UIImage *img =[UIImage imageWithData:plainData];