aboutsummaryrefslogtreecommitdiff
path: root/envelope.cpp
blob: a8cd7935892fd61a59b571b98a7ae5c4aebbda59 (plain)
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
#include <cassert>
#include "aes.h"
#include "base64.h" //TODO: remove
#include "envelope.h"
#include "rng.h"

using namespace std;

namespace Envelope{

	bool safeKey(const string &key){
		//checks against keys 0 and 1, because they don't undergo change in RSA
		int i;
		for(i=0;i<(int)key.size();i++)if(key[i]!=0)break;
		if(i==(int)key.size())return false; //key is 0
		if(i==(int)key.size()-1&&key[i]==1)return false; //key is 1
		return true; //fine
	}

	string encrypt(const string &data,const RSA::PublicKey &pubkey){
		const int keylen=8; //256-bit
		CryptoRng crng;
		string key(4*keylen,'\0');
		do {
			for(int i=0;i<keylen;i++)*(uint32_t*)&key[4*i]=crng.get();
		} while(!safeKey(key));
		//cerr<<"WARNING: using predetermined envelope key"<<endl;
		//key="kaasKAASkaasKAAShalloHALLOhallo!";

		cerr<<"decrkey="<<Base64::encode(key)<<endl;
		
		string payload(AES::encrypt(data,key,AES::AES_256_CBC));
		cerr<<"payload="<<Base64::encode(payload)<<endl;
		Bigint rsadata;
		for(int i=0;i<(int)key.size();i++){
			if(i!=0)rsadata<<=8;
			rsadata+=(uint8_t)key[i];
		}
		cerr<<"rsadata="<<rsadata<<endl;
		// cerr<<"We encrypt:"<<endl<<"  "<<rsadata<<endl;
		Bigint res(RSA::encrypt(rsadata,pubkey));
		// cerr<<"to:"<<endl<<"  "<<res<<endl;
		vector<uint8_t> bytes; //bytes in little-endian order
		while(res!=0){
			bytes.push_back(res.lowdigits()&0xff);
			res>>=8;
		}
		cerr<<"encrkey="<<Base64::encode(string(bytes.rbegin(),bytes.rend()))<<endl;
		payload.reserve(payload.size()+bytes.size()+2);
		for(int i=bytes.size()-1;i>=0;i--)payload.push_back(bytes[i]);
		payload.push_back(bytes.size()>>8);
		payload.push_back((uint8_t)bytes.size()&0xff);

		return payload;
	}

	string decrypt(const string &data,const RSA::PrivateKey &privkey){
		cerr<<"=== DECRYPT ==="<<endl;
		if(data.size()<2)throw invalid_argument("Envelope data length invalid");
		int encrkeylen=((uint16_t)data[data.size()-2]<<8)+(uint16_t)data.back();
		assert(encrkeylen<(1<<16));
		cerr<<"encrkeylen="<<encrkeylen<<endl;
		if((int)data.size()<encrkeylen+2)throw invalid_argument("Envelope key format invalid");
		string encrkey(encrkeylen,'\0');
		for(int i=0;i<encrkeylen;i++){
			encrkey[i]=data[data.size()-2-encrkeylen+i];
		}
		cerr<<"encrkey="<<Base64::encode(encrkey)<<endl;
		Bigint rsadata;
		for(int i=0;i<encrkeylen;i++){
			if(i!=0)rsadata<<=8;
			rsadata+=(uint8_t)encrkey[i];
		}
		Bigint res(RSA::decrypt(rsadata,privkey));
		cerr<<"rsadata="<<res<<endl;
		vector<uint8_t> bytes; //bytes in little-endian order
		while(res!=0){
			bytes.push_back(res.lowdigits()&0xff);
			res>>=8;
		}
		string decrkey(bytes.size(),'\0');
		for(int i=0;i<(int)bytes.size();i++)decrkey[bytes.size()-1-i]=bytes[i];
		cerr<<"decrkey="<<Base64::encode(decrkey)<<endl;
		cerr<<"payload="<<Base64::encode(data.substr(0,data.size()-2-encrkeylen))<<endl;
		return AES::decrypt(data.substr(0,data.size()-2-encrkeylen),decrkey,AES::AES_256_CBC);
	}

}