File: XADWinZipAESHandle.m

package info (click to toggle)
unar 1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 6,664 kB
  • sloc: ansic: 52,939; objc: 39,563; cpp: 4,074; makefile: 99; perl: 10
file content (124 lines) | stat: -rw-r--r-- 2,722 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#import "XADWinZipAESHandle.h"
#import "XADException.h"

@implementation XADWinZipAESHandle

-(id)initWithHandle:(CSHandle *)handle length:(off_t)length password:(NSData *)passdata keyLength:(int)keylength
{
	off_t actuallength=length-keylength/2-12;
	if((self=[super initWithName:[handle name] length:actuallength]))
	{
		parent=[handle retain];
		password=[passdata retain];
		keybytes=keylength;
		startoffs=[handle offsetInFile];

		hmac_inited=hmac_done=hmac_correct=NO;
	}
	return self;
}

-(void)dealloc
{
	[parent release];
	[password release];

	if(hmac_inited) HMAC_CTX_cleanup(&hmac);

	[super dealloc];
}

static void DeriveKey(NSData *password,NSData *salt,int iterations,uint8_t *keybuffer,int keylength)
{
	int blocks=(keylength+19)/20;

//	memset(keybuffer,0,keylength);

	for(int i=0;i<blocks;i++)
	{
		HMAC_CTX hmac;
		uint8_t counter[4]={(i+1)>>24,(i+1)>>16,(i+1)>>8,i+1};
		uint8_t buffer[20];

		HMAC_CTX_init(&hmac);
		HMAC_Init(&hmac,[password bytes],[password length],EVP_sha1());
		HMAC_Update(&hmac,[salt bytes],[salt length]);
		HMAC_Update(&hmac,counter,4);
		HMAC_Final(&hmac,buffer,NULL);
		HMAC_CTX_cleanup(&hmac);

		int blocklen=20;
		if(blocklen+i*20>keylength) blocklen=keylength-i*20;
		memcpy(keybuffer,buffer,blocklen);

		for(int j=1;j<iterations;j++)
		{
			HMAC(EVP_sha1(),[password bytes],[password length],buffer,20,buffer,NULL);
			for(int k=0;k<blocklen;k++) keybuffer[k]^=buffer[k];
		}

		keybuffer+=20;
	}
}

-(void)resetStream
{
	[parent seekToFileOffset:startoffs];

	uint8_t keybuf[2*keybytes+2];
	DeriveKey(password,[parent readDataOfLength:keybytes/2],1000,keybuf,sizeof(keybuf));

	if([parent readUInt16LE]!=keybuf[2*keybytes]+(keybuf[2*keybytes+1]<<8)) [XADException raisePasswordException];

	AES_set_encrypt_key(keybuf,keybytes*8,&key);
	memset(counter,0,16);

	if(hmac_inited) HMAC_CTX_cleanup(&hmac);

	HMAC_CTX_init(&hmac);
	HMAC_Init(&hmac,keybuf+keybytes,keybytes,EVP_sha1());

	hmac_inited=YES;
	hmac_done=NO;
	hmac_correct=NO;
}


-(int)streamAtMost:(int)num toBuffer:(void *)buffer
{
	int actual=[parent readAtMost:num toBuffer:buffer];

	HMAC_Update(&hmac,buffer,actual);

	for(int i=0;i<actual;i++)
	{
		int bufoffs=(i+streampos)%16;
		if(bufoffs==0)
		{
			for(int i=0;i<8;i++) if(++counter[i]!=0) break;
			AES_encrypt(counter,aesbuffer,&key);
		}

		((uint8_t *)buffer)[i]^=aesbuffer[bufoffs];
	}

	return actual;
}

-(BOOL)hasChecksum { return YES; }

-(BOOL)isChecksumCorrect
{
	if(!hmac_done && streampos==streamlength)
	{
		uint8_t filedigest[10],calcdigest[20];
		[parent readBytes:10 toBuffer:filedigest];
		HMAC_Final(&hmac,calcdigest,NULL);
		hmac_correct=memcmp(calcdigest,filedigest,10)==0;
		hmac_done=YES;
	}

	return hmac_correct;
}

@end