aboutsummaryrefslogtreecommitdiff
path: root/envelope.cpp
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2016-10-08 11:59:44 +0200
committertomsmeding <tom.smeding@gmail.com>2016-10-08 11:59:44 +0200
commit113f90b689af1d7169df9db5d7e84443972b5f68 (patch)
tree06cea871ae704f5cb335ea2381fa5dd98e9e62d3 /envelope.cpp
parentddeae250bc6661daafb25ae07f8c2e01b53b0d44 (diff)
Add digital envelope encryption
Diffstat (limited to 'envelope.cpp')
-rw-r--r--envelope.cpp88
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);
+ }
+
+}