在Go语言中使用CFB加密的Objective-C中的CCCryptor解密数据

I've been working on this for a long time, but am stuck.

I'm writing an iOS app that takes AES encrypted data form a Go server-side application and decrypts it. I'm using CCCryptor for the decryption on the iOS side. However, I cannot, for the life of me, get plaintext out. There is a working Java/Android implementation, and it decrypts fine on the Go side, so I'm pretty sure it's to do with my CCCryptor settings.

I'm actually getting a 0 success status on decryption, but taking the output and doing a NSString initWithBytes gives me a null string.

Note: I'm only writing the iOS side.

Go code that encrypts:

func encrypt(key, text []byte) []byte {

  block, err := aes.NewCipher(key)
  if err != nil {
    panic(err)
  }

  b := encodeBase64(text)
  ciphertext := make([]byte, aes.BlockSize+len(b))
  iv := ciphertext[:aes.BlockSize]
  if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    panic(err)
  }

  cfb := cipher.NewCFBEncrypter(block, iv)

  cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))

  return ciphertext
}

Objective-C code that decrypts

+ (NSData *)decrypt:(NSData*)data withPassword:(NSString*)password{


NSData * key = [password dataUsingEncoding:NSUTF8StringEncoding];

size_t dataLength   = [data length] - kCCBlockSizeAES128;
NSData *iv          = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted   = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];

//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];

size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
                                 0x0000, // change to 0 solve the problem
                                 [key bytes],
                                 kCCKeySizeAES256,
                                 [iv bytes],
                                 [encrypted bytes], dataLength, /* input */
                                 [ret mutableBytes], [ret length], /* output */
                                 &numBytesDecrypted
                                 );

NSLog(@"err: %d", status);
NSLog(@"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
    //the returned NSData takes ownership of the buffer and will free it on deallocation
    return ret;
}

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

My recommendation is to use RNCryptor, there is an iOS and a Go implementation available.

RNCryptor combines all the necessary cryptographic primitives for your needs including:

  • AES-256 encryption (Advanced Encryption Standard)
  • CBC mode (Cipher Block Chaining)
  • Password stretching with PBKDF2 (Password Based Key Derivation Function 2)
  • Password salting
  • Random IV (Initialization Vector)
  • Encrypt-then-hash HMAC (Authentication)

It has been extensively deployed and vetted.

It is all to easy to get cryptography wrong and using RNCryptor will avoid the potential pitfalls.

If I had the cryptographic needs you have I would use it.