#import "CryptoTools.h"

#import <OpenSSL/hmac.h>

#import "Constraints.h"
#import "Conversions.h"
#import "EvpMessageDigest.h"
#import "EvpSymetricUtil.h"
#import "Util.h"

@implementation CryptoTools

+(NSData*)generateSecureRandomData:(NSUInteger)length {
    NSMutableData* d = [NSMutableData dataWithLength:length];
    SecRandomCopyBytes(kSecRandomDefault, length, [d mutableBytes]);
    return d;
}

+(uint16_t)generateSecureRandomUInt16 {
    return [[self generateSecureRandomData:sizeof(uint16_t)] bigEndianUInt16At:0];
}

+(NSString*) computeOtpWithPassword:(NSString*)password andCounter:(int64_t)counter {
    require(password != nil);
    
    NSData* d = [[[NSNumber numberWithLongLong:counter] stringValue] encodedAsUtf8];
    NSData* h = [d hmacWithSha1WithKey:[password encodedAsUtf8]];
    return [h encodedAsBase64];
}

@end

@implementation NSData (CryptoUtil)

-(NSData*)hmacWithSha1WithKey:(NSData*)key {
    return [EvpMessageDigest hmacUsingSha1Data:self withKey:key];
}

-(NSData*)hmacWithSha256WithKey:(NSData*)key {
    return [EvpMessageDigest hmacUsingSha256Data:self withKey:key];
}

-(NSData*)encryptWithAesInCipherFeedbackModeWithKey:(NSData*)key andIv:(NSData*)iv {
    return [EvpSymetricUtil encryptMessage:self usingAes128WithCfbAndKey:key andIv:iv];
}
-(NSData*)encryptWithAesInCipherBlockChainingModeWithPkcs7PaddingWithKey:(NSData*)key andIv:(NSData*)iv {
    return [EvpSymetricUtil encryptMessage:self usingAes128WithCbcAndPaddingAndKey:key andIv:iv];
}
-(NSData*)encryptWithAesInCounterModeWithKey:(NSData*)key andIv:(NSData*)iv {
    return [EvpSymetricUtil encryptMessage:self usingAes128InCounterModeAndKey:key andIv:iv];
}

-(NSData*)decryptWithAesInCipherFeedbackModeWithKey:(NSData*)key andIv:(NSData*)iv {
    return [EvpSymetricUtil decryptMessage:self usingAes128WithCfbAndKey:key andIv:iv];
}
-(NSData*)decryptWithAesInCipherBlockChainingModeWithPkcs7PaddingWithKey:(NSData*)key andIv:(NSData*)iv {
    return [EvpSymetricUtil decryptMessage:self usingAes128WithCbcAndPaddingAndKey:key andIv:iv];
}
-(NSData*)decryptWithAesInCounterModeWithKey:(NSData*)key andIv:(NSData*)iv {
    return [EvpSymetricUtil decryptMessage:self usingAes128InCounterModeAndKey:key andIv:iv];
}

-(NSData*)hashWithSha256 {
    return [EvpMessageDigest hashWithSha256:self];
}
-(bool)isEqualToData_TimingSafe:(NSData*)other {
    if (other == nil) return false;
    NSUInteger n = [self length];
    if ([other length] != n) return false;
    bool equal = true;
    for (NSUInteger i = 0; i < n; i++)
        equal &= [self uint8At:i] == [other uint8At:i];
    return equal;
}
@end
