/*---------------------------------------------------------------------------*/
/* Cipher.m                                                                  */
/* copyright (c) innovaphone 2015                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#import <Foundation/Foundation.h>

#import "platform/platform.h"
#import "platform/IosNamespace.h"
#import "Cipher.h"

@interface Cipher()

@property (nonatomic) bool encrypt;
@property (nonatomic) NSMutableData *dataS;
@property (nonatomic) NSMutableData *dataT;
@property (nonatomic) int keyLen;

+ (id) Cipher;

- (id) init;

@end
@implementation Cipher

+ (id) Cipher
{
    return [[self alloc] init];
}

- (id) init
{
    self = [super init];
    if (self) {
        Cipher *__weak weakSelf = self;
        _Init = ^ void (int type, const byte * key, int keyLen, bool encrypt) { [weakSelf Init_:type key:key keyLen:keyLen encrypt:encrypt]; };
        _Crypt = ^ void (const byte * in, byte * out, int len) { [weakSelf Crypt_:in out:out len:len]; };

        self.encrypt = false;
        self.dataS = [NSMutableData dataWithCapacity:256]; 
        self.dataT = [NSMutableData dataWithCapacity:256]; 
        self.keyLen = 0;
    }
    return self;
}


- (void) Init_:(int)cipher_type key:(const byte *)key keyLen:(int)keyLen encrypt:(bool)encrypt
{
    byte *S = (byte *)(self.dataS.mutableBytes);
    byte *T = (byte *)(self.dataT.mutableBytes);
    self.keyLen = keyLen;
    for (int i = 0; i < 256; i++) {
        S[i] = (byte) i;
        T[i] = key[i % self.keyLen];
    }
    int j = 0;
    for (int i = 0; i < 256; i++) {
        j = (j + S[i] + T[i]) & 0xff;
        byte temp = S[i];
        S[i] = S[j];
        S[j] = temp;
    }
}

- (void) Crypt_:(const byte *)in out:(byte *)out len:(int)len
{
    byte *S = (byte *)(self.dataS.mutableBytes);
    int i = 0, j = 0, k, t;
    for (int counter = 0; counter < len; counter++) {
        i = (i + 1) & 0xff;
        j = (j + S[i]) & 0xff;
        byte temp = S[i];
        S[i] = S[j];
        S[j] = temp;
        t = (S[i] + S[j]) & 0xff;
        k = S[t];
        out[counter] = (byte) (in[counter] ^ k);
    }
}

@end
