-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Note text encryption #231
base: master
Are you sure you want to change the base?
Note text encryption #231
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
#include "vigenere.h" | ||
#include <iostream> | ||
#include <string> | ||
#include <vector> | ||
|
||
|
||
class Base64 | ||
{ | ||
public: | ||
static std::string encode(const std::vector<char>& data); | ||
static std::vector<char> decode(const std::string& data); | ||
}; | ||
|
||
|
||
const char fillchar = '='; | ||
|
||
// 00000000001111111111222222 | ||
// 01234567890123456789012345 | ||
static std::string cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||
|
||
// 22223333333333444444444455 | ||
// 67890123456789012345678901 | ||
"abcdefghijklmnopqrstuvwxyz" | ||
|
||
// 555555556666 | ||
// 234567890123 | ||
"0123456789+/"; | ||
|
||
// | ||
//----< convert vector of bytes to std::string >--------------------- | ||
|
||
std::string Base64::encode(const std::vector<char>& data) | ||
{ | ||
std::string::size_type i; | ||
char c; | ||
unsigned int len = data.size(); | ||
std::string ret; | ||
|
||
for (i = 0; i < len; ++i) | ||
{ | ||
c = (data[i] >> 2) & 0x3f; | ||
ret.append(1, cvt[c]); | ||
c = (data[i] << 4) & 0x3f; | ||
if (++i < len) | ||
c |= (data[i] >> 4) & 0x0f; | ||
|
||
ret.append(1, cvt[c]); | ||
if (i < len) | ||
{ | ||
c = (data[i] << 2) & 0x3f; | ||
if (++i < len) | ||
c |= (data[i] >> 6) & 0x03; | ||
|
||
ret.append(1, cvt[c]); | ||
} | ||
else | ||
{ | ||
++i; | ||
ret.append(1, fillchar); | ||
} | ||
|
||
if (i < len) | ||
{ | ||
c = data[i] & 0x3f; | ||
ret.append(1, cvt[c]); | ||
} | ||
else | ||
{ | ||
ret.append(1, fillchar); | ||
} | ||
} | ||
|
||
return(ret); | ||
} | ||
// | ||
//----< convert std::string to vector of bytes >--------------------- | ||
|
||
std::vector<char> Base64::decode(const std::string& data) | ||
{ | ||
std::string::size_type i; | ||
char c; | ||
char c1; | ||
std::string::size_type len = data.length(); | ||
std::vector<char> ret; | ||
|
||
for (i = 0; i < len; ++i) | ||
{ | ||
c = (char) cvt.find(data[i]); | ||
++i; | ||
c1 = (char) cvt.find(data[i]); | ||
c = (c << 2) | ((c1 >> 4) & 0x3); | ||
ret.push_back(c); | ||
if (++i < len) | ||
{ | ||
c = data[i]; | ||
if (fillchar == c) | ||
break; | ||
c = (char) cvt.find(c); | ||
c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf); | ||
ret.push_back(c1); | ||
} | ||
if (++i < len) | ||
{ | ||
c1 = data[i]; | ||
if (fillchar == c1) | ||
break; | ||
c1 = (char) cvt.find(c1); | ||
c = ((c << 6) & 0xc0) | c1; | ||
ret.push_back(c); | ||
} | ||
} | ||
return(ret); | ||
} | ||
|
||
|
||
// encrypt | ||
|
||
std::string encrypt(std::string& msg, std::string& key) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use some built-in strong encryption algorithm? "Home made cryptography" is discouraged. Please use some vetted stable library to do encryption and decryption. |
||
{ | ||
std::vector<char> msg2(msg.begin(), msg.end()); | ||
std::string b64_str = Base64::encode(msg2); | ||
std::string vigenere_msg = encrypt_vigenere(b64_str, key); | ||
return vigenere_msg; | ||
} | ||
|
||
// https://stackoverflow.com/questions/17316506/strip-invalid-utf8-from-string-in-c-c | ||
std::string sanitize_utf8(std::string& str) | ||
{ | ||
int i,f_size=str.size(); | ||
unsigned char c,c2,c3,c4; | ||
string to; | ||
to.reserve(f_size); | ||
|
||
for(i=0 ; i<f_size ; i++){ | ||
c=(unsigned char)(str)[i]; | ||
if(c<32){//control char | ||
if(c==9 || c==10 || c==13){//allow only \t \n \r | ||
to.append(1,c); | ||
} | ||
continue; | ||
}else if(c<127){//normal ASCII | ||
to.append(1,c); | ||
continue; | ||
}else if(c<160){//control char (nothing should be defined here either ASCI, ISO_8859-1 or UTF8, so skipping) | ||
if(c2==128){//fix microsoft mess, add euro | ||
to.append(1,226); | ||
to.append(1,130); | ||
to.append(1,172); | ||
} | ||
if(c2==133){//fix IBM mess, add NEL = \n\r | ||
to.append(1,10); | ||
to.append(1,13); | ||
} | ||
continue; | ||
}else if(c<192){//invalid for UTF8, converting ASCII | ||
to.append(1,(unsigned char)194); | ||
to.append(1,c); | ||
continue; | ||
}else if(c<194){//invalid for UTF8, converting ASCII | ||
to.append(1,(unsigned char)195); | ||
to.append(1,c-64); | ||
continue; | ||
}else if(c<224 && i+1<f_size){//possibly 2byte UTF8 | ||
c2=(unsigned char)(str)[i+1]; | ||
if(c2>127 && c2<192){//valid 2byte UTF8 | ||
if(c==194 && c2<160){//control char, skipping | ||
; | ||
}else{ | ||
to.append(1,c); | ||
to.append(1,c2); | ||
} | ||
i++; | ||
continue; | ||
} | ||
}else if(c<240 && i+2<f_size){//possibly 3byte UTF8 | ||
c2=(unsigned char)(str)[i+1]; | ||
c3=(unsigned char)(str)[i+2]; | ||
if(c2>127 && c2<192 && c3>127 && c3<192){//valid 3byte UTF8 | ||
to.append(1,c); | ||
to.append(1,c2); | ||
to.append(1,c3); | ||
i+=2; | ||
continue; | ||
} | ||
}else if(c<245 && i+3<f_size){//possibly 4byte UTF8 | ||
c2=(unsigned char)(str)[i+1]; | ||
c3=(unsigned char)(str)[i+2]; | ||
c4=(unsigned char)(str)[i+3]; | ||
if(c2>127 && c2<192 && c3>127 && c3<192 && c4>127 && c4<192){//valid 4byte UTF8 | ||
to.append(1,c); | ||
to.append(1,c2); | ||
to.append(1,c3); | ||
to.append(1,c4); | ||
i+=3; | ||
continue; | ||
} | ||
} | ||
//invalid UTF8, converting ASCII (c>245 || string too short for multi-byte)) | ||
to.append(1,(unsigned char)195); | ||
to.append(1,c-64); | ||
} | ||
return to; | ||
} | ||
|
||
|
||
std::string decrypt(std::string& encrypted_msg, std::string& key) | ||
{ | ||
std::string newKey = extend_key(encrypted_msg, key); | ||
std::string b64_encoded_str = decrypt_vigenere(encrypted_msg, newKey); | ||
std::vector<char> b64_decode_vec = Base64::decode(b64_encoded_str); | ||
std::string b64_decode_str(b64_decode_vec.begin(), b64_decode_vec.end()); | ||
return sanitize_utf8(b64_decode_str); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
***********************************************************************************/ | ||
|
||
#include <QTimer> | ||
#include <stdio.h> | ||
|
||
#include "syncrunner.h" | ||
#include "src/global.h" | ||
|
@@ -34,6 +35,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
#include "src/communication/communicationmanager.h" | ||
#include "src/communication/communicationerror.h" | ||
#include "src/sql/nsqlquery.h" | ||
#include "encrypt.h" | ||
|
||
#define CRYPT_KEY "6aabbb3efbd1ff6d606061684e9749cd476763a8" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The encryption key should never be checked in the version control. This defeats the whole purpose of encryption. Even if the code were not public, it still would only be an obfuscation. |
||
|
||
extern Global global; | ||
|
||
|
@@ -583,6 +587,30 @@ void SyncRunner::syncRemoteNotes(QList<Note> notes, qint32 account) { | |
|
||
for (int i = 0; i < notes.size() && keepRunning; i++) { | ||
Note t = notes[i]; | ||
|
||
//QLOG_DEBUG() << t.content; | ||
|
||
// decrypt ============================================= | ||
int crypt_s = t.content->indexOf("||crypt||"); | ||
if (crypt_s!=-1) { | ||
int crypt_e = t.content->indexOf("</en-note>"); | ||
QString cryptq = t.content->mid(crypt_s + 9, crypt_e - crypt_s - 9); | ||
cryptq.remove(QChar('\n')); | ||
|
||
//QLOG_DEBUG() << cryptq; | ||
|
||
string crypt = cryptq.toStdString(); | ||
string crypt_key = CRYPT_KEY; | ||
string msg = decrypt(crypt, crypt_key); | ||
|
||
notes[i].content = QString::fromUtf8(msg.c_str()); | ||
|
||
t = notes[i]; | ||
|
||
//QLOG_DEBUG() << t.content; | ||
} | ||
// ====================================================== | ||
|
||
qint32 lid = noteTable.getLid(t.guid); | ||
if (lid > 0) { | ||
// Find out if it is a conflicting change | ||
|
@@ -1184,6 +1212,29 @@ qint32 SyncRunner::uploadPersonalNotes() { | |
Note note; | ||
noteTable.get(note, validLids[i], true, true); | ||
|
||
// encrypt content ============================ | ||
//QLOG_DEBUG() << note.content; | ||
|
||
int crypt_tag = note.content->indexOf("{{encrypt}}"); | ||
|
||
if (crypt_tag != -1){ | ||
string msg = note.content->toStdString(); | ||
string crypt_key = CRYPT_KEY; | ||
string crypt = encrypt(msg, crypt_key); | ||
|
||
note.content = QString::fromUtf8(crypt.c_str()); | ||
|
||
note.content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"\ | ||
"<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>"\ | ||
"<en-note style=\n\"word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;\">\n"\ | ||
"||crypt||" + | ||
note.content + | ||
"</en-note>"; | ||
|
||
//QLOG_DEBUG() << note.content; | ||
} | ||
////============================================ | ||
|
||
qint32 oldUsn = 0; | ||
if (note.updateSequenceNum.isSet()) | ||
oldUsn = note.updateSequenceNum; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <string> | ||
#include <iostream> | ||
#include <stdio.h> | ||
#include <ctype.h> | ||
|
||
using namespace std; | ||
|
||
std::string AVAILABLE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | ||
|
||
int index(char c) { | ||
for(int ii = 0; ii < AVAILABLE_CHARS.size(); ii++) { | ||
if(AVAILABLE_CHARS[ii] == c) { | ||
// std::cout << ii << " " << c << std::endl; | ||
return ii; | ||
} | ||
} | ||
return -1; | ||
} | ||
|
||
|
||
std::string extend_key(std::string& msg, std::string& key) { | ||
//generating new key | ||
int msgLen = msg.size(); | ||
std::string newKey(msgLen, 'x'); | ||
int keyLen = key.size(), i, j; | ||
for(i = 0, j = 0; i < msgLen; ++i, ++j){ | ||
if(j == keyLen) | ||
j = 0; | ||
|
||
newKey[i] = key[j]; | ||
} | ||
newKey[i] = '\0'; | ||
return newKey; | ||
} | ||
|
||
|
||
std::string encrypt_vigenere(std::string& msg, std::string& key) { | ||
int msgLen = msg.size(), keyLen = key.size(), i, j; | ||
std::string encryptedMsg(msgLen, 'x'); | ||
// char newKey[msgLen], encryptedMsg[msgLen], decryptedMsg[msgLen]; | ||
|
||
std::string newKey = extend_key(msg, key); | ||
|
||
//encryption | ||
for(i = 0; i < msgLen; ++i) { | ||
// std::cout << msg[i] << " " << isalnum(msg[i]) << std::endl; | ||
if(isalnum(msg[i]) or msg[i] == ' ') { | ||
encryptedMsg[i] = AVAILABLE_CHARS[((index(msg[i]) + index(newKey[i])) % AVAILABLE_CHARS.size())]; | ||
} else { | ||
encryptedMsg[i] = msg[i]; | ||
} | ||
} | ||
|
||
encryptedMsg[i] = '\0'; | ||
return encryptedMsg; | ||
} | ||
|
||
std::string decrypt_vigenere(std::string& encryptedMsg, std::string& newKey) { | ||
// decryption | ||
int msgLen = encryptedMsg.size(); | ||
std::string decryptedMsg(msgLen, 'x'); | ||
int i; | ||
for(i = 0; i < msgLen; ++i) { | ||
if(isalnum(encryptedMsg[i]) or encryptedMsg[i] == ' ') { | ||
decryptedMsg[i] = AVAILABLE_CHARS[(((index(encryptedMsg[i]) - index(newKey[i])) + AVAILABLE_CHARS.size()) % AVAILABLE_CHARS.size())]; | ||
} else { | ||
decryptedMsg[i] = encryptedMsg[i]; | ||
} | ||
} | ||
decryptedMsg[i] = '\0'; | ||
return decryptedMsg; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why code (body of functions) is in a header file?