diff options
author | tomsmeding <tom.smeding@gmail.com> | 2016-10-08 11:59:44 +0200 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2016-10-08 11:59:44 +0200 |
commit | 113f90b689af1d7169df9db5d7e84443972b5f68 (patch) | |
tree | 06cea871ae704f5cb335ea2381fa5dd98e9e62d3 /envelope.cpp | |
parent | ddeae250bc6661daafb25ae07f8c2e01b53b0d44 (diff) |
Add digital envelope encryption
Diffstat (limited to 'envelope.cpp')
-rw-r--r-- | envelope.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/envelope.cpp b/envelope.cpp new file mode 100644 index 0000000..a8cd793 --- /dev/null +++ b/envelope.cpp @@ -0,0 +1,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); + } + +} |