CCCrypto解密:少一个块

huangapple go评论99阅读模式
英文:

CCCrypto decrypt: exactly one block less

问题

我正在尝试解密由golang脚本加密的字符串。加密方式是CBC,密钥长度为256位。16字节长的IV包含在密文的开头,正如golang文档建议的那样。除了objc代码总是丢失最后一个块之外,一切都正常。例如,当我期望返回80字节时,只得到64字节,期望返回128字节时,只得到112字节。有什么建议吗?谢谢!

golang代码

func encrypt(text_s, key_s string) []byte {

    text := []byte(text_s)

    // 填充文本
    n := aes.BlockSize - (len(text) % aes.BlockSize)
    log.Println("需要填充:", n)

    if n != aes.BlockSize || n != 0 {
        text = append([]byte(strings.Repeat(" ", n)), text...)
    }

    log.Println("要加密的文本:'", string(text), "'")
    log.Println("填充后的长度:", len(text))

    key := []byte(key_s)[:32]
    block, _ := aes.NewCipher(key)

    // if err != nil {
    // 	panic(err)
    // }

    ret := make([]byte, aes.BlockSize+len(text))
    iv := ret[:aes.BlockSize]

    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        panic(err)
    }

    cbc := cipher.NewCBCEncrypter(block, iv)
    cbc.CryptBlocks(ret[aes.BlockSize:], text)

    return ret
}

objc代码:

- (NSData *)decrypt:(NSData*)data{
    if (!key) {
        key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
    }
    
//    NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
//    NSString *key = _token;
//    
//    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
//    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    
//    BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
//    NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//    
//    if (patchNeeded) {
//        key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
//    }
    
    // fetch key data
//    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
    
//    if (patchNeeded) {
//        // Previous iOS version than iOS7 set the first char to '
- (NSData *)decrypt:(NSData*)data{
    if (!key) {
        key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
    }
    
//    NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
//    NSString *key = _token;
//    
//    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
//    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    
//    BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
//    NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//    
//    if (patchNeeded) {
//        key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
//    }
    
    // fetch key data
//    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
    
//    if (patchNeeded) {
//        // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
//        keyPtr[0] = '\0';  
//    }
    
    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,
                                          kCCOptionPKCS7Padding,
                                          [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;
}
' if the key was longer than kCCKeySizeAES256
// keyPtr[0] = '
- (NSData *)decrypt:(NSData*)data{
    if (!key) {
        key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
    }
    
//    NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
//    NSString *key = _token;
//    
//    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
//    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    
//    BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
//    NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//    
//    if (patchNeeded) {
//        key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
//    }
    
    // fetch key data
//    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
    
//    if (patchNeeded) {
//        // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
//        keyPtr[0] = '\0';  
//    }
    
    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,
                                          kCCOptionPKCS7Padding,
                                          [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;
}
';
// } 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, kCCOptionPKCS7Padding, [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; }
英文:

I'm trying to decrypt string encrypted by golang script. The encryption is CBC, key size 256. 16 bytes long iv is include at the beginning of ciphered text, as golang doc suggested. Everything works fine except the objc codes always lost the last block. e.g. when I expect 80 bytes return but only get 64, expect 128 but get 112. any advice? thanks!

golang code

func encrypt(text_s, key_s string) byte[] {

    text := []byte(text_s)

    // padding text
    n := aes.BlockSize - (len(text) % aes.BlockSize)
    log.Println("Need to pad:", n)

    if n != aes.BlockSize || n != 0 {
        text = append([]byte(strings.Repeat(" ", n)), text...)
    }

    log.Println("to encrypt:'", string(text), "'")
    log.Println("padded length:", len(text))

    key  := []byte(key_s)[:32]
    block, _ := aes.NewCipher(key)

	// if err != nil {
	// 	panic(err)
	// }

	ret := make([]byte, aes.BlockSize + len(text))
	iv  := ret[:aes.BlockSize]

	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	cbc := cipher.NewCBCEncrypter(block, iv)
	cbc.CryptBlocks(ret[aes.BlockSize:], text)

	return ret
}

objc codes:

    - (NSData *)decrypt:(NSData*)data{
    if (!key) {
        key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
    }
    
//    NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
//    NSString *key = _token;
//    
//    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
//    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    
//    BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
//    NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//    
//    if (patchNeeded) {
//        key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
//    }
    
    // fetch key data
//    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
    
//    if (patchNeeded) {
//        // Previous iOS version than iOS7 set the first char to '
    - (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
//    NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
//    NSString *key = _token;
//    
//    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
//    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
//    BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
//    NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//    
//    if (patchNeeded) {
//        key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
//    }
// fetch key data
//    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
//    if (patchNeeded) {
//        // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
//        keyPtr[0] = '\0';  
//    }
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,
kCCOptionPKCS7Padding,
[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;
}
' if the key was longer than kCCKeySizeAES256 // keyPtr[0] = '
    - (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
//    NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
//    NSString *key = _token;
//    
//    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
//    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
//    BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
//    NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//    
//    if (patchNeeded) {
//        key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
//    }
// fetch key data
//    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
//    if (patchNeeded) {
//        // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
//        keyPtr[0] = '\0';  
//    }
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,
kCCOptionPKCS7Padding,
[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;
}
'; // } 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, kCCOptionPKCS7Padding, [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; }

答案1

得分: 0

问题出在解密选项上:

CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
                                          0, // 将其改为0可以解决问题
                                          [key bytes],
                                          kCCKeySizeAES256,
                                          [iv bytes],
                                          [encrypted bytes], dataLength, /* 输入 */
                                          [ret mutableBytes], [ret length], /* 输出 */
                                          &numBytesDecrypted
                                          );
英文:

it turns out the problem is with the decryption option:

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

huangapple
  • 本文由 发表于 2014年2月19日 08:05:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/21868286.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定