#import #import #import #import NS_ASSUME_NONNULL_BEGIN @interface MTBignumImpl : NSObject { @public BIGNUM *_value; } @end @implementation MTBignumImpl - (instancetype)init { self = [super init]; if (self != nil) { _value = BN_new(); } return self; } - (instancetype)initWithValue:(BIGNUM *)value { self = [super init]; if (self != nil) { _value = value; } return self; } - (void)dealloc { BN_clear_free(_value); } - (instancetype)copyWithZone:(NSZone * _Nullable)__unused zone { return [[MTBignumImpl alloc] initWithValue:BN_dup(_value)]; } @end @interface MTRsaPublicKeyImpl : NSObject { @public RSA *_value; } @end @implementation MTRsaPublicKeyImpl - (instancetype)initWithValue:(RSA *)value { self = [super init]; if (self != nil) { _value = value; } return self; } - (void)dealloc { RSA_free(_value); } @end @interface MTBignumContextImpl : NSObject { BN_CTX *_context; } @end @implementation MTBignumContextImpl - (instancetype)init { self = [super init]; if (self != nil) { _context = BN_CTX_new(); } return self; } - (void)dealloc { BN_CTX_free(_context); } - (id)create { return [[MTBignumImpl alloc] init]; } - (id)clone:(id)other { assert([other isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *otherImpl = other; return [otherImpl copy]; } - (void)setConstantTime:(id)other { assert([other isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *otherImpl = other; #ifndef TELEGRAM_USE_BORINGSSL BN_set_flags(otherImpl->_value, BN_FLG_CONSTTIME); #endif } - (void)assignWordTo:(id)bignum value:(unsigned long)value { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; BN_set_word(bignumImpl->_value, value); } - (void)assignHexTo:(id)bignum value:(NSString *)value { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; BN_hex2bn(&bignumImpl->_value, [value UTF8String]); } - (void)assignBinTo:(id)bignum value:(NSData *)value { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; BN_bin2bn(value.bytes, value.length, bignumImpl->_value); } - (void)assignOneTo:(id)bignum { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; BN_one(bignumImpl->_value); } - (void)assignZeroTo:(id)bignum { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; BN_zero(bignumImpl->_value); } - (bool)isOne:(id)bignum { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; return BN_is_one(bignumImpl->_value); } - (bool)isZero:(id)bignum { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; return BN_is_zero(bignumImpl->_value); } - (NSData *)getBin:(id)bignum { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; int numBytes = BN_num_bytes(bignumImpl->_value); NSMutableData *data = [[NSMutableData alloc] initWithLength:numBytes]; BN_bn2bin(bignumImpl->_value, data.mutableBytes); return data; } - (int)isPrime:(id)bignum numberOfChecks:(int)numberOfChecks { assert([bignum isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *bignumImpl = bignum; return BN_is_prime_ex(bignumImpl->_value, numberOfChecks, _context, NULL); } - (int)compare:(id)a with:(id)b { assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; return BN_cmp(aImpl->_value, bImpl->_value); } - (bool)modAddInto:(id)result a:(id)a b:(id)b mod:(id)mod { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); assert([mod isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; MTBignumImpl *modImpl = mod; return BN_mod_add(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0; } - (bool)modSubInto:(id)result a:(id)a b:(id)b mod:(id)mod { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); assert([mod isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; MTBignumImpl *modImpl = mod; return BN_mod_sub(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0; } - (bool)modMulInto:(id)result a:(id)a b:(id)b mod:(id)mod { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); assert([mod isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; MTBignumImpl *modImpl = mod; return BN_mod_mul(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0; } - (bool)modExpInto:(id)result a:(id)a b:(id)b mod:(id)mod { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); assert([mod isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; MTBignumImpl *modImpl = mod; return BN_mod_exp(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0; } - (bool)addInto:(id)result a:(id)a b:(id)b { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; return BN_add(resultImpl->_value, aImpl->_value, bImpl->_value) != 0; } - (bool)subInto:(id)result a:(id)a b:(id)b { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; return BN_sub(resultImpl->_value, aImpl->_value, bImpl->_value) != 0; } - (bool)mulInto:(id)result a:(id)a b:(id)b { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; return BN_mul(resultImpl->_value, aImpl->_value, bImpl->_value, _context) != 0; } - (bool)expInto:(id)result a:(id)a b:(id)b { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([b isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *bImpl = b; return BN_exp(resultImpl->_value, aImpl->_value, bImpl->_value, _context) != 0; } - (bool)modInverseInto:(id)result a:(id)a mod:(id)mod { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); assert([mod isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; MTBignumImpl *modImpl = mod; return BN_mod_inverse(resultImpl->_value, aImpl->_value, modImpl->_value, _context) != 0; } - (unsigned long)modWord:(id)a mod:(unsigned long)mod { assert([a isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *aImpl = a; return BN_mod_word(aImpl->_value, mod); } - (bool)rightShift1Bit:(id)result a:(id)a { assert([result isKindOfClass:[MTBignumImpl class]]); assert([a isKindOfClass:[MTBignumImpl class]]); MTBignumImpl *resultImpl = result; MTBignumImpl *aImpl = a; return BN_rshift1(resultImpl->_value, aImpl->_value); } - (id)rsaGetE:(id)publicKey { assert([publicKey isKindOfClass:[MTRsaPublicKeyImpl class]]); MTRsaPublicKeyImpl *publicKeyImpl = publicKey; return [[MTBignumImpl alloc] initWithValue:BN_dup(RSA_get0_e(publicKeyImpl->_value))]; } - (id)rsaGetN:(id)publicKey { assert([publicKey isKindOfClass:[MTRsaPublicKeyImpl class]]); MTRsaPublicKeyImpl *publicKeyImpl = publicKey; return [[MTBignumImpl alloc] initWithValue:BN_dup(RSA_get0_n(publicKeyImpl->_value))]; } @end @implementation OpenSSLEncryptionProvider - (id)createBignumContext { return [[MTBignumContextImpl alloc] init]; } - (NSData * _Nullable)rsaEncryptWithPublicKey:(NSString *)publicKey data:(NSData *)data { MTRsaPublicKeyImpl *rsaKey = [self parseRSAPublicKey:publicKey]; if (rsaKey == nil) { return nil; } MTBignumContextImpl *context = [[MTBignumContextImpl alloc] init]; MTBignumImpl *a = [context create]; [context assignBinTo:a value:data]; MTBignumImpl *r = [context create]; [context modExpInto:r a:a b:[context rsaGetE:rsaKey] mod:[context rsaGetN:rsaKey]]; return [context getBin:r]; } - (NSData * _Nullable)rsaEncryptPKCS1OAEPWithPublicKey:(NSString *)publicKey data:(NSData *)data { MTRsaPublicKeyImpl *rsaKey = [self parseRSAPublicKey:publicKey]; if (rsaKey == nil) { return nil; } NSMutableData *outData = [[NSMutableData alloc] initWithLength:data.length + 2048]; int encryptedLength = RSA_public_encrypt((int)data.length, data.bytes, outData.mutableBytes, rsaKey->_value, RSA_PKCS1_OAEP_PADDING); if (encryptedLength < 0) { return nil; } assert(encryptedLength <= outData.length); [outData setLength:encryptedLength]; return outData; } - (id)parseRSAPublicKey:(NSString *)publicKey { BIO *keyBio = BIO_new(BIO_s_mem()); NSData *keyData = [publicKey dataUsingEncoding:NSUTF8StringEncoding]; if (keyData == nil) { return nil; } BIO_write(keyBio, keyData.bytes, (int)keyData.length); RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL); BIO_free(keyBio); if (rsaKey == nil) { return nil; } return [[MTRsaPublicKeyImpl alloc] initWithValue:rsaKey]; } -(NSData *)macosRSAEncrypt:(NSString *) publicKey data: (NSData *)data { BIO *keyBio = BIO_new(BIO_s_mem()); const char *keyData = [publicKey UTF8String]; BIO_write(keyBio, keyData, (int)publicKey.length); RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL); BIO_free(keyBio); BN_CTX *ctx = BN_CTX_new(); BIGNUM *a = BN_bin2bn(data.bytes, (int)data.length, NULL); BIGNUM *r = BN_new(); BN_mod_exp(r, a, RSA_get0_e(rsaKey), RSA_get0_n(rsaKey), ctx); unsigned char *res = malloc((size_t)BN_num_bytes(r)); int resLen = BN_bn2bin(r, res); BN_CTX_free(ctx); BN_free(a); BN_free(r); RSA_free(rsaKey); NSData *result = [[NSData alloc] initWithBytesNoCopy:res length:(NSUInteger)resLen freeWhenDone:true]; return result; } @end NS_ASSUME_NONNULL_END