mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
328 lines
8.8 KiB
Objective-C
328 lines
8.8 KiB
Objective-C
#import "MTAes.h"
|
|
|
|
#import <CommonCrypto/CommonCrypto.h>
|
|
|
|
# define AES_MAXNR 14
|
|
# define AES_BLOCK_SIZE 16
|
|
|
|
#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
|
|
typedef struct {
|
|
unsigned long data[N_WORDS];
|
|
} aes_block_t;
|
|
|
|
/* XXX: probably some better way to do this */
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
# define UNALIGNED_MEMOPS_ARE_FAST 1
|
|
#else
|
|
# define UNALIGNED_MEMOPS_ARE_FAST 0
|
|
#endif
|
|
|
|
#if UNALIGNED_MEMOPS_ARE_FAST
|
|
# define load_block(d, s) (d) = *(const aes_block_t *)(s)
|
|
# define store_block(d, s) *(aes_block_t *)(d) = (s)
|
|
#else
|
|
# define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE)
|
|
# define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE)
|
|
#endif
|
|
|
|
void MyAesIgeEncrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
|
|
int len;
|
|
size_t n;
|
|
void const *inB;
|
|
void *outB;
|
|
|
|
unsigned char aesIv[AES_BLOCK_SIZE];
|
|
memcpy(aesIv, iv, AES_BLOCK_SIZE);
|
|
unsigned char ccIv[AES_BLOCK_SIZE];
|
|
memcpy(ccIv, iv + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
|
|
|
assert(((size_t)inBytes | (size_t)outBytes | (size_t)aesIv | (size_t)ccIv) % sizeof(long) ==
|
|
0);
|
|
|
|
void *tmpInBytes = malloc(length);
|
|
len = length / AES_BLOCK_SIZE;
|
|
inB = inBytes;
|
|
outB = tmpInBytes;
|
|
|
|
aes_block_t *inp = (aes_block_t *)inB;
|
|
aes_block_t *outp = (aes_block_t *)outB;
|
|
for (n = 0; n < N_WORDS; ++n) {
|
|
outp->data[n] = inp->data[n];
|
|
}
|
|
|
|
--len;
|
|
inB += AES_BLOCK_SIZE;
|
|
outB += AES_BLOCK_SIZE;
|
|
void const *inBCC = inBytes;
|
|
|
|
aes_block_t const *iv3p = (aes_block_t *)ccIv;
|
|
|
|
if (len > 0) {
|
|
while (len) {
|
|
aes_block_t *inp = (aes_block_t *)inB;
|
|
aes_block_t *outp = (aes_block_t *)outB;
|
|
|
|
for (n = 0; n < N_WORDS; ++n) {
|
|
outp->data[n] = inp->data[n] ^ iv3p->data[n];
|
|
}
|
|
|
|
iv3p = inBCC;
|
|
--len;
|
|
inBCC += AES_BLOCK_SIZE;
|
|
inB += AES_BLOCK_SIZE;
|
|
outB += AES_BLOCK_SIZE;
|
|
}
|
|
}
|
|
|
|
size_t realOutLength = 0;
|
|
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0, key, keyLength, aesIv, tmpInBytes, length, outBytes, length, &realOutLength);
|
|
free(tmpInBytes);
|
|
|
|
assert(result == kCCSuccess);
|
|
|
|
len = length / AES_BLOCK_SIZE;
|
|
|
|
aes_block_t const *ivp = inB;
|
|
aes_block_t *iv2p = (aes_block_t *)ccIv;
|
|
|
|
inB = inBytes;
|
|
outB = outBytes;
|
|
|
|
while (len) {
|
|
aes_block_t *inp = (aes_block_t *)inB;
|
|
aes_block_t *outp = (aes_block_t *)outB;
|
|
|
|
for (n = 0; n < N_WORDS; ++n) {
|
|
outp->data[n] ^= iv2p->data[n];
|
|
}
|
|
ivp = outp;
|
|
iv2p = inp;
|
|
--len;
|
|
inB += AES_BLOCK_SIZE;
|
|
outB += AES_BLOCK_SIZE;
|
|
}
|
|
|
|
memcpy(iv, ivp->data, AES_BLOCK_SIZE);
|
|
memcpy(iv + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
|
|
}
|
|
|
|
void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
|
|
assert(length % 16 == 0);
|
|
assert(length >= 0);
|
|
|
|
unsigned char aesIv[AES_BLOCK_SIZE];
|
|
memcpy(aesIv, iv, AES_BLOCK_SIZE);
|
|
unsigned char ccIv[AES_BLOCK_SIZE];
|
|
memcpy(ccIv, iv + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
|
|
|
assert(((size_t)inBytes | (size_t)outBytes | (size_t)aesIv | (size_t)ccIv) % sizeof(long) ==
|
|
0);
|
|
|
|
CCCryptorRef decryptor = NULL;
|
|
CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &decryptor);
|
|
if (decryptor != NULL) {
|
|
int len;
|
|
size_t n;
|
|
|
|
len = length / AES_BLOCK_SIZE;
|
|
|
|
aes_block_t *ivp = (aes_block_t *)(aesIv);
|
|
aes_block_t *iv2p = (aes_block_t *)(ccIv);
|
|
|
|
while (len) {
|
|
aes_block_t tmp;
|
|
aes_block_t *inp = (aes_block_t *)inBytes;
|
|
aes_block_t *outp = (aes_block_t *)outBytes;
|
|
|
|
for (n = 0; n < N_WORDS; ++n)
|
|
tmp.data[n] = inp->data[n] ^ iv2p->data[n];
|
|
|
|
size_t dataOutMoved = 0;
|
|
CCCryptorStatus result = CCCryptorUpdate(decryptor, &tmp, AES_BLOCK_SIZE, outBytes, AES_BLOCK_SIZE, &dataOutMoved);
|
|
assert(result == kCCSuccess);
|
|
assert(dataOutMoved == AES_BLOCK_SIZE);
|
|
|
|
for (n = 0; n < N_WORDS; ++n)
|
|
outp->data[n] ^= ivp->data[n];
|
|
|
|
ivp = inp;
|
|
iv2p = outp;
|
|
|
|
inBytes += AES_BLOCK_SIZE;
|
|
outBytes += AES_BLOCK_SIZE;
|
|
|
|
--len;
|
|
}
|
|
|
|
memcpy(iv, ivp->data, AES_BLOCK_SIZE);
|
|
memcpy(iv + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
|
|
|
|
CCCryptorRelease(decryptor);
|
|
}
|
|
}
|
|
|
|
void MyAesCbcDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
|
|
size_t outLength = 0;
|
|
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, key, keyLength, iv, inBytes, length, outBytes, length, &outLength);
|
|
assert(status == kCCSuccess);
|
|
assert(outLength == length);
|
|
}
|
|
|
|
static void ctr128_inc(unsigned char *counter)
|
|
{
|
|
uint32_t n = 16, c = 1;
|
|
|
|
do {
|
|
--n;
|
|
c += counter[n];
|
|
counter[n] = (uint8_t)c;
|
|
c >>= 8;
|
|
} while (n);
|
|
}
|
|
|
|
static void ctr128_inc_aligned(unsigned char *counter)
|
|
{
|
|
size_t *data, c, d, n;
|
|
const union {
|
|
long one;
|
|
char little;
|
|
} is_endian = {
|
|
1
|
|
};
|
|
|
|
if (is_endian.little || ((size_t)counter % sizeof(size_t)) != 0) {
|
|
ctr128_inc(counter);
|
|
return;
|
|
}
|
|
|
|
data = (size_t *)counter;
|
|
c = 1;
|
|
n = 16 / sizeof(size_t);
|
|
do {
|
|
--n;
|
|
d = data[n] += c;
|
|
/* did addition carry? */
|
|
c = ((d - c) ^ d) >> (sizeof(size_t) * 8 - 1);
|
|
} while (n);
|
|
}
|
|
|
|
|
|
@interface MTAesCtr () {
|
|
CCCryptorRef _cryptor;
|
|
|
|
unsigned char _ivec[16] __attribute__((aligned(16)));
|
|
unsigned int _num;
|
|
unsigned char _ecount[16] __attribute__((aligned(16)));
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MTAesCtr
|
|
|
|
- (instancetype)initWithKey:(const void *)key keyLength:(int)keyLength iv:(const void *)iv decrypt:(bool)decrypt {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
_num = 0;
|
|
memset(_ecount, 0, 16);
|
|
memcpy(_ivec, iv, 16);
|
|
|
|
CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &_cryptor);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithKey:(const void *)key keyLength:(int)keyLength iv:(const void *)iv ecount:(void *)ecount num:(uint32_t)num {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
_num = num;
|
|
memcpy(_ecount, ecount, 16);
|
|
memcpy(_ivec, iv, 16);
|
|
|
|
CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &_cryptor);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
if (_cryptor) {
|
|
CCCryptorRelease(_cryptor);
|
|
}
|
|
}
|
|
|
|
- (uint32_t)num {
|
|
return _num;
|
|
}
|
|
|
|
- (void *)ecount {
|
|
return _ecount;
|
|
}
|
|
|
|
- (void)getIv:(void *)iv {
|
|
memcpy(iv, _ivec, 16);
|
|
}
|
|
|
|
- (void)encryptIn:(const unsigned char *)in out:(unsigned char *)out len:(size_t)len {
|
|
unsigned int n;
|
|
size_t l = 0;
|
|
|
|
assert(in);
|
|
assert(out);
|
|
assert(_num < 16);
|
|
|
|
n = _num;
|
|
|
|
if (16 % sizeof(size_t) == 0) { /* always true actually */
|
|
do {
|
|
while (n && len) {
|
|
*(out++) = *(in++) ^ _ecount[n];
|
|
--len;
|
|
n = (n + 1) % 16;
|
|
}
|
|
|
|
if (((size_t)in|(size_t)out|(size_t)_ivec)%sizeof(size_t) != 0)
|
|
break;
|
|
|
|
while (len >= 16) {
|
|
size_t dataOutMoved;
|
|
CCCryptorUpdate(_cryptor, _ivec, 16, _ecount, 16, &dataOutMoved);
|
|
ctr128_inc_aligned(_ivec);
|
|
for (n = 0; n < 16; n += sizeof(size_t)) {
|
|
*(size_t *)(out + n) =
|
|
*(size_t *)(in + n) ^ *(size_t *)(_ecount + n);
|
|
}
|
|
len -= 16;
|
|
out += 16;
|
|
in += 16;
|
|
n = 0;
|
|
}
|
|
if (len) {
|
|
size_t dataOutMoved;
|
|
CCCryptorUpdate(_cryptor, _ivec, 16, _ecount, 16, &dataOutMoved);
|
|
ctr128_inc_aligned(_ivec);
|
|
while (len--) {
|
|
out[n] = in[n] ^ _ecount[n];
|
|
++n;
|
|
}
|
|
}
|
|
_num = n;
|
|
return;
|
|
} while (0);
|
|
}
|
|
/* the rest would be commonly eliminated by x86* compiler */
|
|
|
|
while (l < len) {
|
|
if (n == 0) {
|
|
size_t dataOutMoved;
|
|
CCCryptorUpdate(_cryptor, _ivec, 16, _ecount, 16, &dataOutMoved);
|
|
ctr128_inc(_ivec);
|
|
}
|
|
out[l] = in[l] ^ _ecount[n];
|
|
++l;
|
|
n = (n + 1) % 16;
|
|
}
|
|
|
|
_num = n;
|
|
}
|
|
|
|
@end
|