diff --git a/harbour-sailotp.pro b/harbour-sailotp.pro index 5fd0cba..5f94e3d 100644 --- a/harbour-sailotp.pro +++ b/harbour-sailotp.pro @@ -4,6 +4,7 @@ DEFINES += APP_VERSION=\\\"$$VERSION\\\" DEFINES += APP_BUILDNUM=\\\"$$RELEASE\\\" CONFIG += sailfishapp +PKGCONFIG += libcrypto SOURCES += src/harbour-sailotp.cpp @@ -21,7 +22,6 @@ DISTFILES += qml/harbour-sailotp.qml \ qml/lib/urldecoder.js \ qml/lib/storage.js \ qml/lib/crypto.js \ - qml/lib/cryptojs-aes.js \ qml/lib/sha.js \ qml/sailotp.png \ rpm/harbour-sailotp.spec \ @@ -48,4 +48,5 @@ TRANSLATIONS = translations/harbour-sailotp-de.ts \ include(src/qzxing/QZXing.pri) include(src/FileIO/FileIO.pri) +include(src/QCipher/QCipher.pri) include(src/qqrencode/qqrencode.pri) diff --git a/qml/lib/cryptojs-aes.js b/qml/lib/cryptojs-aes.js deleted file mode 100644 index 827503c..0000000 --- a/qml/lib/cryptojs-aes.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -CryptoJS v3.1.2 -code.google.com/p/crypto-js -(c) 2009-2013 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, -r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< -32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j>>3]|=parseInt(a.substr(j, -2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}}, -q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w< -l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})(); -(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])}, -_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]), -f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f, -m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m, -E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/ -4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math); -(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a, -this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684, -1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})}, -decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d, -b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}(); -(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8, -16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;dd||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>> -8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t= -d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})(); diff --git a/qml/pages/ExportPage.qml b/qml/pages/ExportPage.qml index 131a60f..98962fe 100644 --- a/qml/pages/ExportPage.qml +++ b/qml/pages/ExportPage.qml @@ -28,11 +28,12 @@ */ -import QtQuick 2.0 +import QtQuick 2.2 import Sailfish.Silica 1.0 +import Sailfish.Pickers 1.0 import harbour.sailotp.FileIO 1.0 // Import FileIO Class +import harbour.sailotp.QCipher 1.0 // Import FileIO Class import "../lib/storage.js" as DB // Import the storage library for Config-Access -import "../lib/cryptojs-aes.js" as CryptoJS //Import AES encryption library // Define Layout of the Export / Import Page Dialog { @@ -82,6 +83,11 @@ Dialog { onError: { console.log(msg); } } + // QCipher Object for Encryption + QCipher { + id: cipher + } + SilicaFlickable { id: exportFlickable anchors.fill: parent @@ -101,7 +107,7 @@ Dialog { VerticalScrollDecorator {} - Column { + Column { anchors.fill: parent DialogHeader { acceptText: mode == "export" ? qsTr("Export") : qsTr("Import") @@ -186,7 +192,7 @@ Dialog { color: Theme.secondaryColor visible: mode == "export" - text: qsTr("Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export.")+"\n\n"+qsTr("To view the content of the export file outside of SailOTP use the following openssl command:") + "\n\nopenssl enc -d -a -A -md md5 -aes-256-cbc -in " + text: qsTr("Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export.")+"\n\n"+qsTr("To view the content of the export file outside of SailOTP use the following openssl command:") + "\n\nopenssl enc -d -a -aes-256-cbc -in " } } } @@ -206,7 +212,7 @@ Dialog { if (plainText != "") { try { - chipherText = CryptoJS.CryptoJS.AES.encrypt(plainText, filePassword.text); + chipherText = cipher.encrypt(plainText, filePassword.text); if (!exportFile.write(chipherText)) { notify.show(qsTr("Error writing to file ")+ fileName.text, 4000); } else { @@ -225,7 +231,7 @@ Dialog { if (chipherText != "") { try { var errormsg = "" - plainText = CryptoJS.CryptoJS.AES.decrypt(chipherText, filePassword.text).toString(CryptoJS.CryptoJS.enc.Utf8); + plainText = cipher.decrypt(chipherText, filePassword.text) if (DB.json2db(plainText, errormsg)) { notify.show(qsTr("Tokens imported from ")+ fileName.text, 4000); } else { diff --git a/rpm/harbour-sailotp.yaml b/rpm/harbour-sailotp.yaml index c2eb444..3ebdef7 100644 --- a/rpm/harbour-sailotp.yaml +++ b/rpm/harbour-sailotp.yaml @@ -26,6 +26,7 @@ PkgConfigBR: - Qt5Core - Qt5Multimedia - sailfishapp >= 1.0.2 + - libcrypto Requires: - sailfishsilica-qt5 >= 0.10.9 diff --git a/src/FileIO/src/fileio.cpp b/src/FileIO/src/fileio.cpp index 146bc74..dee8e78 100644 --- a/src/FileIO/src/fileio.cpp +++ b/src/FileIO/src/fileio.cpp @@ -52,7 +52,7 @@ QString FileIO::read() QTextStream t( &file ); do { line = t.readLine(); - fileContent += line; + fileContent += line + "\n"; } while (!line.isNull()); file.close(); diff --git a/src/QCipher/QCipher.pri b/src/QCipher/QCipher.pri new file mode 100644 index 0000000..6ca19e0 --- /dev/null +++ b/src/QCipher/QCipher.pri @@ -0,0 +1,9 @@ +QT += core quick + +INCLUDEPATH += $$PWD/src + +HEADERS += $$PWD/src/cipher.h \ + $$PWD/src/qcipher.h + +SOURCES += $$PWD/src/cipher.cpp \ + $$PWD/src/qcipher.cpp diff --git a/src/QCipher/README.md b/src/QCipher/README.md new file mode 100644 index 0000000..7fbaab1 --- /dev/null +++ b/src/QCipher/README.md @@ -0,0 +1,3 @@ +# QChipher - a minimal OpenSSL Encryption / Decryption Wrapper + +Based on https://github.com/jlinoff/openssl-aes-cipher by Joe Linoff diff --git a/src/QCipher/src/cipher.cpp b/src/QCipher/src/cipher.cpp new file mode 100644 index 0000000..5425400 --- /dev/null +++ b/src/QCipher/src/cipher.cpp @@ -0,0 +1,476 @@ +// ================================================================ +// Description: Cipher class. +// Copyright: Copyright (c) 2012 by Joe Linoff +// Version: 1.3.0 +// Author: Joe Linoff +// +// LICENSE +// The cipher package is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// The cipher package is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. You should have received +// a copy of the GNU General Public License along with the change +// tool; if not, write to the Free Software Foundation, Inc., 59 +// Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// ================================================================ +#include "cipher.h" +#include +#include +#include +#include +#include +#include +#include +#include // strlen +#include // getenv +#include // getdomainname +#include +#include +#include +#include +#include +using namespace std; + +// ================================================================ +// MACROS +// ================================================================ +#define DBG_PRE __FILE__ << ":" << __LINE__ << ": " +#define DBG_FCT(fct) if(m_debug) cout << DBG_PRE << "FCT " << fct << endl +#define DBG_TDUMP(v) if(m_debug) tdump(__FILE__, __LINE__, #v, v) +#define DBG_PKV(v) if(m_debug) vdump(__FILE__, __LINE__, #v, v) +#define DBG_PKVR(k, v) if(m_debug) vdump(__FILE__, __LINE__, k, v) +#define DBG_BDUMP(a, x) if(m_debug) bdump(__FILE__, __LINE__, #a, a, x) +#define DBG_MDUMP(a) if(m_debug) bdump(__FILE__, __LINE__, #a, (unsigned char*)a.c_str(), a.size()) +#define DBG_MADEIT cout << DBG_PRE << "MADE IT" << endl +#define PKV(v) vdump(__FILE__, __LINE__, #v, v) + +#define SALTED_PREFIX "Salted__" + +namespace +{ + // ================================================================ + // DEBUG mode only. + // Formated dump of a general type. + // ================================================================ + template void vdump(const string& fn, + uint ln, + const string& prefix, + const T& d) + { + cout << fn << ":" << ln << ": " << prefix << "\t" << d << endl; + } + // ================================================================ + // DEBUG mode only. + // Explicit template instantiation of the above for string + // types so that I can report the length. + // ================================================================ + template<> void vdump(const string& fn, + uint ln, + const string& prefix, + const string& d) + { + cout << fn << ":" << ln << ": " + << prefix << "\t" + << left << setw(64) << d + << " (" << d.size() << ")" + << endl; + } + // ================================================================ + // DEBUG mode only. + // Dump for fixed sized types like m_salt and m_key. + // ================================================================ + template void tdump(const string& fn, + uint ln, + const string& prefix, + const T& d) + { + cout << fn << ":" << ln << ": " << prefix << "\t"; + for(uint i=0;ilength; + char* mimetext = new char[len+1]; + memcpy(mimetext, bptr->data, bptr->length-1); + mimetext[bptr->length-1]=0; + BIO_free_all(b64); + + string ret = mimetext; + delete [] mimetext; + return ret; +} + +// ================================================================ +// decode_base64 +// ================================================================ +Cipher::kv1_t Cipher::decode_base64(const string& mimetext) const +{ + DBG_FCT("decode_base64"); + kv1_t x; + int SZ=mimetext.size(); // this will always be smaller + x.first = new uchar[SZ]; + char* tmpbuf = new char[SZ+1]; + + strcpy(tmpbuf, mimetext.c_str()); + + BIO* b64 = BIO_new(BIO_f_base64()); + BIO* bm = BIO_new_mem_buf(tmpbuf, mimetext.size()); + bm = BIO_push(b64, bm); + + if (SZ <= 64) { + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + } + + x.second = BIO_read(bm, x.first, SZ); + BIO_free_all(bm); + delete [] tmpbuf; + return x; +} + +// ================================================================ +// encode_cipher +// ================================================================ +Cipher::kv1_t Cipher::encode_cipher(const string& plaintext) const +{ + DBG_FCT("encode_cipher"); + uint SZ = plaintext.size() + AES_BLOCK_SIZE + 20; // leave some padding + uchar* ciphertext = new uchar[SZ]; + bzero(ciphertext, SZ); + uchar* pbeg = ciphertext; + + // This requires some explanation. + // In order to be compatible with openssl, I need to append + // 16 characters worth of information that describe the salt. + // I found this in the openssl source code but I couldn't + // find any associated documentation. + uint off = 0; + if (m_embed) { + memcpy(&ciphertext[0], SALTED_PREFIX, 8); + memcpy(&ciphertext[8], m_salt, 8); + off = 16; + ciphertext += off; + } + + int ciphertext_len=0; + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + const EVP_CIPHER* cipher = EVP_aes_256_cbc(); + EVP_CIPHER_CTX_init(ctx); + if (1 != EVP_EncryptInit_ex(ctx, cipher, NULL, m_key, m_iv)) { + EVP_CIPHER_CTX_free(ctx); + throw runtime_error("EVP_EncryptInit_ex DBG_PKV() init key/iv failed"); + } + EVP_CIPHER_CTX_set_key_length(ctx, EVP_MAX_KEY_LENGTH); + + // Encrypt the plaintext data all at once. + // It would be straightforward to chunk it but that + // add unecesary complexity at this point. + uchar* pt_buf = (uchar*)plaintext.c_str(); + uint pt_len = plaintext.size(); + if (1 != EVP_EncryptUpdate(ctx, ciphertext, &ciphertext_len, pt_buf, pt_len)) { + EVP_CIPHER_CTX_free(ctx); + throw runtime_error("EVP_EncryptUpdate() failed"); + } + + uchar* pad_buf = ciphertext + ciphertext_len; // pad at the end + int pad_len=0; + if (1 != EVP_EncryptFinal_ex(ctx, pad_buf, &pad_len)) { + EVP_CIPHER_CTX_free(ctx); + throw runtime_error("EVP_EncryptFinal_ex() failed"); + } + + ciphertext_len += pad_len + off; // for the Salted prefix + EVP_CIPHER_CTX_free(ctx); + return kv1_t(pbeg, ciphertext_len); +} + +// ================================================================ +// decode_cipher +// ================================================================ +string Cipher::decode_cipher(uchar* ciphertext, + uint ciphertext_len) const +{ + DBG_FCT("decode_cipher"); + const uint SZ = ciphertext_len+20; + uchar* plaintext = new uchar[SZ]; + int plaintext_len = 0; + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + + bzero(plaintext, SZ); + EVP_CIPHER_CTX_init(ctx); + + if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, m_key, m_iv)) { + EVP_CIPHER_CTX_free(ctx); + throw runtime_error("EVP_DecryptInit_ex() failed"); + } + //EVP_CIPHER_CTX_set_key_length(ctx, EVP_MAX_KEY_LENGTH); + + if (1 != EVP_DecryptUpdate(ctx, plaintext, &plaintext_len, ciphertext, ciphertext_len)) { + EVP_CIPHER_CTX_free(ctx); + throw runtime_error("EVP_DecryptUpdate() failed"); + } + + int plaintext_padlen=0; + if (1 != EVP_DecryptFinal_ex(ctx, plaintext+plaintext_len, &plaintext_padlen)) { + ERR_print_errors_fp(stderr); + EVP_CIPHER_CTX_free(ctx); + throw runtime_error("EVP_DecryptFinal_ex() failed"); + } + plaintext_len += plaintext_padlen; + plaintext[plaintext_len] = 0; + + string ret = (char*)plaintext; + delete [] plaintext; + EVP_CIPHER_CTX_free(ctx); + return ret; +} + +// ================================================================ +// set_salt +// ================================================================ +void Cipher::set_salt(const string& salt) +{ + DBG_FCT("set_salt"); + if (salt.length() == 0) { + // Choose a random salt. + for(uint i=0;i8) { + throw overflow_error("init(): salt is too long, must be 8 characters"); + } +} + +// ================================================================ +// init() +// ================================================================ +void Cipher::init(const string& pass) +{ + DBG_FCT("init"); + + // Use a default passphrase if the user didn't specify one. + m_pass = pass; + if (m_pass.empty() ) { + // Default: ' deFau1t pASsw0rD' + // Obfuscate so that a simple strings will not find it. + char a[] = {' ', 'd', 'e', 'F', 'a', 'u', '1', 't', ' ', + 'p', 'A', 'S', 's', 'w', '0', 'r', 'D', 0}; + m_pass = a; + } + + // Create the key and IV values from the passkey. + bzero(m_key, sizeof(m_key)); + bzero(m_iv, sizeof(m_iv)); + OpenSSL_add_all_algorithms(); + const EVP_CIPHER* cipher = EVP_get_cipherbyname(m_cipher.c_str()); + const EVP_MD* digest = EVP_get_digestbyname(m_digest.c_str()); + if (!cipher) { + string msg = "init(): cipher does not exist "+m_cipher; + throw runtime_error(msg); + } + if (!digest) { + string msg = "init(): digest does not exist "+m_digest; + throw runtime_error(msg); + } + + int ks = EVP_BytesToKey(cipher, // cipher type + digest, // message digest + m_salt, // 8 bytes + (uchar*)m_pass.c_str(), // pass value + m_pass.length(), + m_count, // number of rounds + m_key, + m_iv); + if (ks!=32) { + throw runtime_error("init() failed: " + "EVP_BytesToKey did not return a 32 byte key"); + } + + DBG_PKV(m_pass); + DBG_PKV(m_cipher); + DBG_PKV(m_digest); + DBG_TDUMP(m_salt); + DBG_TDUMP(m_key); + DBG_TDUMP(m_iv); + DBG_PKV(m_count); +} + +// ================================================================ +// get_version +// ================================================================ +std::string Cipher::get_version() { + return "1.3.0"; +} + +// ================================================================ +// get_ssl_version +// ================================================================ +#define TO_STRING_(x) #x +#define TO_STRING(x) TO_STRING_(x) +std::string Cipher::get_ssl_version() { + return TO_STRING(OPENSSL_VERSION_NUMBER); +} diff --git a/src/QCipher/src/cipher.h b/src/QCipher/src/cipher.h new file mode 100644 index 0000000..a16245e --- /dev/null +++ b/src/QCipher/src/cipher.h @@ -0,0 +1,208 @@ +// ================================================================ +// Description: Cipher class. +// Copyright: Copyright (c) 2012 by Joe Linoff +// Version: 1.3.0 +// Author: Joe Linoff +// +// LICENSE +// The cipher package is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// The cipher package is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. You should have received +// a copy of the GNU General Public License along with the change +// tool; if not, write to the Free Software Foundation, Inc., 59 +// Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// ================================================================ +#ifndef cipher_h +#define cipher_h + +#include +#include +#include // pair + +#define CIPHER_DEFAULT_CIPHER "aes-256-cbc" +#define CIPHER_DEFAULT_DIGEST "sha256" +#define CIPHER_DEFAULT_COUNT 1 + +/** + * The cipher object encrypts plaintext data or decrypts ciphertext + * data. All data is in ASCII because it is MIME encoded. + * + * The default cipher used is AES-256-CBC from the openssl library + * but there are many others available. The default digest used is + * SHA256 which is stronger than MD5. + * + * The algorithms mimic openssl so files created with this object + * and with the openssl tool are interchangeable. + * + * Here is how you would use it to encrypt and decrypt plaintext + * data in memory. + * @code + * #include "cipher.h" + * #include + * using namepsace std; + * + * // Example the encrypts and decrypts some plaintext. + * // Use encrypt_file or decrypt_file to deal with files. + * void cipher_test() + * { + * string pass = "testTEST!23_"; + * string salt = "12345678"; // must be 8 chars + * string plaintext = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + * + * // Encrypt and decrypt. + * Cipher c; + * string ciphertext = c.encrypt(plaintext ,pass,salt); + * string decoded = c.decrypt(ciphertext,pass,salt); + * + * // Test the results + * if (plaintext == decoded) { + * cout << "passed" << endl; + * } + * else { + * cout << "failed" << endl; + * } + * } + * @endcode + * @author Joe Linoff + */ +class Cipher +{ +public: + typedef unsigned int uint; + typedef unsigned char uchar; + typedef uchar aes_key_t[32]; + typedef uchar aes_iv_t[32]; + typedef uchar aes_salt_t[8]; + typedef std::pair kv1_t; +public: + /** + * Constructor. + */ + Cipher(); + + /** + * Constructor. + * @param cipher The cipher algorithm to use (ex. aes-256-cbc). + * @param digest The digest to use (ex. sha256). + * @param count The number of iterations (def. 1). + * @param embed Embed the salt. If this is false, the output will + * not be compatible with openssl. + */ + Cipher(const std::string& cipher, + const std::string& digest, + uint count=1, + bool embed=true); + + /** + * Destructor. + */ + ~Cipher(); +public: + /** + * Encrypt buffer using AES 256 CBC (SHA256). + * @param plaintext The plaintext buffer. + * @param pass The passphrase. + * @param salt The optional salt. + * @returns The ciphertext: encrypted, MIME encoded data. + */ + std::string encrypt(const std::string& plaintext, + const std::string& pass="", + const std::string& salt=""); + +public: + /** + * Decrypt a buffer using AES 256 CBC (SHA256). + * @param ciphertext The encrypted data. + * @param pass The passphrase. + * @param salt The optional salt. + * @returns The plaintext: decrypted, MIME decoded data. + */ + std::string decrypt(const std::string& ciphertext, + const std::string& pass="", + const std::string& salt=""); + +public: + /** + * Base64 encode. + * @param ciphertext Binary cipher text. + * @param ciphertext_len Length of cipher buffer. + * @returns The encoded ASCII MIME string. + */ + std::string encode_base64(uchar* ciphertext, + uint ciphertext_len) const; + + /** + * Cipher encode. + * @param plaintext ASCII data to encode. + * @returns Binary data. + */ + kv1_t encode_cipher(const std::string& plaintext) const; + + /** + * Base64 decode. + * @param mimetext ASCII MIME text. + * @returns Binary data. + */ + kv1_t decode_base64(const std::string& mimetext) const; + + /** + * Cipher decode. + * @param ciphertext Binary cipher text. + * @param ciphertext_len Length of cipher buffer. + * @returns The decoded ASCII string. + */ + std::string decode_cipher(uchar* ciphertext, + uint ciphertext_len) const; +public: + /** + * Get the version of this class. + * @returns The version of the class. + */ + static std::string get_version(); + /** + * Get the version of ssl. + */ + static std::string get_ssl_version(); +public: + /** + * Set the internal debug flag. + * This is only useful for library developers. + * @param b True for debug or false otherwise. + */ + void debug(bool b=true) {m_debug=b;} + /** + * Is debug mode set? + * @returns The current debug mode. + */ + bool debug() const {return m_debug;} +private: + /** + * Convert string salt to internal format. + * @param salt The salt. + */ + void set_salt(const std::string& salt); + /** + * Initialize the cipher: set the key and IV values. + * @param pass The passphrase. + */ + void init(const std::string& pass); + +private: + std::string m_pass; + std::string m_cipher; + std::string m_digest; + aes_salt_t m_salt; + aes_key_t m_key; + aes_iv_t m_iv; + uint m_count; + bool m_embed; + bool m_debug; +}; + +#endif diff --git a/src/QCipher/src/qcipher.cpp b/src/QCipher/src/qcipher.cpp new file mode 100644 index 0000000..84b698b --- /dev/null +++ b/src/QCipher/src/qcipher.cpp @@ -0,0 +1,20 @@ +#include "qcipher.h" + +QCipher::QCipher(QObject *parent) : QObject(parent) +{ + c = Cipher("aes-256-cbc", "sha256"); +} + +QString QCipher::encrypt(QString plaintext, QString pass) +{ + std::string enc; + enc = c.encrypt(plaintext.toStdString(), pass.toStdString()); + return QString::fromUtf8(enc.c_str()); +} + +QString QCipher::decrypt(QString ciphertext, QString pass) +{ + std::string dec; + dec = c.decrypt(ciphertext.toStdString(), pass.toStdString()); + return QString::fromUtf8(dec.c_str()); +}; diff --git a/src/QCipher/src/qcipher.h b/src/QCipher/src/qcipher.h new file mode 100644 index 0000000..ac9a734 --- /dev/null +++ b/src/QCipher/src/qcipher.h @@ -0,0 +1,24 @@ +#ifndef QCIPHER_H +#define QCIPHER_H + +#include +#include +#include "cipher.h" + +class QCipher : public QObject +{ + Q_OBJECT +public: + explicit QCipher(QObject *parent = nullptr); + + Q_INVOKABLE QString encrypt(QString plaintext, QString pass); + Q_INVOKABLE QString decrypt(QString ciphertext, QString pass); + +private: + Cipher c; + +signals: + +}; + +#endif // QCIPHER_H diff --git a/src/harbour-sailotp.cpp b/src/harbour-sailotp.cpp index ffe1c0e..09bd660 100644 --- a/src/harbour-sailotp.cpp +++ b/src/harbour-sailotp.cpp @@ -31,6 +31,7 @@ #include #include #include "fileio.h" +#include "qcipher.h" #include "qzxing.h" #include "qqrencode.h" @@ -58,6 +59,8 @@ int main(int argc, char *argv[]) // Register FileIO Class qmlRegisterType("harbour.sailotp.FileIO", 1, 0, "FileIO"); + // Register QCipher Class + qmlRegisterType("harbour.sailotp.QCipher", 1, 0, "QCipher"); // Prepare the QML and set Homedir view->setSource(SailfishApp::pathTo("qml/harbour-sailotp.qml")); diff --git a/translations/harbour-sailotp-de.ts b/translations/harbour-sailotp-de.ts index 64e4900..ae20bd3 100644 --- a/translations/harbour-sailotp-de.ts +++ b/translations/harbour-sailotp-de.ts @@ -188,109 +188,109 @@ Gewählte Datei existiert nicht! - - + + Export Export - - + + Import Import - + Filename Dateiname - + File to import Aus Datei importieren - + File to export In Datei exportieren - + Overwrite existing Existierende überschreiben - + Password Passwort - + Password for the file Passwort für die Datei - + Passwords don't match! Passwörter nicht identisch! - + Passwords match! Passwörter identisch! - + Repeated Password for the file Passwort wiederholen - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Hier können Tokens aus einer Datei importiert werden. Gib die Datei und das beim Export gewählte Passwort ein. Nach links ziehen um zu starten. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Hier können Tokens in eine Datei exportiert werden. Die Datei wird mit AES-256-CBC verschlüsselt und Base64-kodiert. Wähle ein starkes Passwort, die Datei enthält die geheimen Schlüssel zur Erzeugung der Tokens für deine Accounts. Nach links ziehen um zu starten. - + To view the content of the export file outside of SailOTP use the following openssl command: Mit folgendem Openssl-Befehl kann der Inhalt der Exportdatei außerhalb von SailOTP angezeigt werden: - + Error writing to file Fehler beim Schreiben der Datei - + Token Database exported to Datenbank exportiert nach - + Could not encrypt tokens. Error: Fehler beim Verschlüsseln. Fehler: - + Could not read tokens from Database Datenbank konnte nicht gelesen werden - + Tokens imported from Tokens importiert aus - + Unable to decrypt file, did you use the right password? Fehler beim entschlüsseln, falsches Passwort? - + Could not read from file Datei konnte nicht gelesen werden diff --git a/translations/harbour-sailotp-es.ts b/translations/harbour-sailotp-es.ts index 3a26b6e..c6d9eba 100644 --- a/translations/harbour-sailotp-es.ts +++ b/translations/harbour-sailotp-es.ts @@ -188,109 +188,109 @@ ¡El fichero proporcionado no exsiste! - - + + Export Exportar - - + + Import Importar - + Filename Nombre del fichero - + File to import Fichero a importar - + File to export Fichero a exportar - + Overwrite existing Sobreescribir existente - + Password Contraseña - + Password for the file Contraseña para el fichero - + Passwords don't match! ¡Las contraseñas no coinciden! - + Passwords match! ¡Las contraseñas coinciden! - + Repeated Password for the file Contraseña repetida para el archivo - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Aquí puede Importar Tokens desde un fichero. Ponga la localización del fichero y la contraseña utilizada en la exportación. Tire hacia la izquierda para comenzar la importación. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Aquí puede exportar Tokens a un fichero. El fichero exportado será encriptado con AES-256-CBC y codificado en Base64. Escoja una contraseña segura, el fichero contendrá las cadenas secretas utilizadas para la generación de los Tokens. Tire hacia la izquierda para comenzar la exportación. - + To view the content of the export file outside of SailOTP use the following openssl command: Para ver los contenidos del fichero de exportación fuera de SailOTP utilize el siguiente comando openssl: - + Error writing to file Error escribiendo el fichero - + Token Database exported to Base de datos de Tokens exportada en - + Could not encrypt tokens. Error: No se ha podido encriptar los tokens. Error: - + Could not read tokens from Database No se ha podido leer los tokens desde la Base de datos - + Tokens imported from Tokens importados desde - + Unable to decrypt file, did you use the right password? No se ha podido desencriptar el fichero, ¿ha utilizado el password correcto? - + Could not read from file No se ha podido leer desde el fichero diff --git a/translations/harbour-sailotp-fi.ts b/translations/harbour-sailotp-fi.ts index b45141c..8ffce04 100644 --- a/translations/harbour-sailotp-fi.ts +++ b/translations/harbour-sailotp-fi.ts @@ -188,109 +188,109 @@ Tiedostoa ei ole olemassa! - - + + Export Vie - - + + Import Tuo - + Filename Tiedoston nimi - + File to import Tuotava tiedosto - + File to export Vietävä tiedosto - + Overwrite existing Ylikirjoita tiedosto - + Password Salasana - + Password for the file Tiedoston salasana - + Passwords don't match! Salasanat eivät täsmää! - + Passwords match! Salasanat täsmäävät! - + Repeated Password for the file Tiedoston salasanan vahvistus - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Voit tuoda tunnuksia tiedostosta. Anna tiedoston polku sekä salasana, jonka annoit vientiä tehdessäsi. Pyyhkäise vasemmalle aloittaaksesi tuonnin. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Voit viedä tunnukset tiedostoon. Vientitiedosto salataan AES-256-CBC-salauksella ja koodataan Base64-koodauksella. Valitse vahva salasana, koska tiedosto sisältää käyttäjätiliesi tunnukset. Pyyhkäise vasemmalle aloittaaksesi viennin. - + To view the content of the export file outside of SailOTP use the following openssl command: Jos haluat tarkastella vientitiedoston sisältöä SailOTP:n ulkopuolella, käytä seuraavaa OpenSSL-komentoa: - + Error writing to file Virhe kirjoitettaessa tiedostoa - + Token Database exported to Tunnustietokanta viety tiedostoon - + Could not encrypt tokens. Error: Tunnusten salaaminen epäonnistui. Virhe: - + Could not read tokens from Database Tunnusten lukeminen tietokannasta epäonnistui - + Tokens imported from Tunnukset tuotu tiedostosta - + Unable to decrypt file, did you use the right password? Tiedoston salauksen purkaminen epäonnistui. Tarkista salasana. - + Could not read from file Tiedoston lukeminen epäonnistui diff --git a/translations/harbour-sailotp-fr.ts b/translations/harbour-sailotp-fr.ts index d22db35..4efc23f 100644 --- a/translations/harbour-sailotp-fr.ts +++ b/translations/harbour-sailotp-fr.ts @@ -188,110 +188,110 @@ Le fichier spécifé n'existe pas ! - - + + Import Importer - - + + Export Exporter - + Filename Nom du fichier - + File to import Fichier à importer - + File to export Fichier à exporter - + Overwrite existing Écraser un fichier existant - + Password Mot de passe - + Password for the file Mot de passe pour le fichier - + Passwords don't match! Les mots de passe ne correspondent pas ! - + Passwords match! Les mots de passe correspondent ! - + Repeated Password for the file Confirmation du mot de passe pour le fichier - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Vous pouvez ici importer les paramètres d'OTP depuis un fichier. Indiquez le fichier et le mot de passe utilisés lors de l'export. Glissez vers la droite pour démarrer l'import. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Vous pouvez ici exporter les paramètres d'OTP vers un fichier. Ce fichier sera chiffré en AES-256-CBC et encodé en Base64. Ce fichier contiendra les secrets utilisés pour générer les OTP de vos comptes, choisissez donc un mot de passe fort. Glissez vers la droite pour démarrer l'export. - + To view the content of the export file outside of SailOTP use the following openssl command: Translated using Google Translate Pour afficher le contenu du fichier d'exportation en dehors de SailOTP, utilisez la commande openssl suivante: - + Error writing to file Erreur lors de l'écriture du fichier - + Token Database exported to Base des paramètres d'OTP exportée vers - + Could not encrypt tokens. Error: Impossible de chiffrer les paramètes d'OTP. Erreur : - + Could not read tokens from Database Impossible de lire les paramètres d'OTP depuis la base de données - + Tokens imported from Paramètres d'OTP importés depuis - + Unable to decrypt file, did you use the right password? Impossible de déchiffrer le fichier, utilisez-vous le bon mot de passe ? - + Could not read from file Impossible de lire depuis le fichier diff --git a/translations/harbour-sailotp-hu.ts b/translations/harbour-sailotp-hu.ts index c187eff..e4b8cc5 100644 --- a/translations/harbour-sailotp-hu.ts +++ b/translations/harbour-sailotp-hu.ts @@ -188,109 +188,109 @@ Az adott fájl nem létezik! - - + + Export Exportálás - - + + Import Importálás - + Filename Fájlnév - + File to import Importálandó fájl - + File to export Exportálandó fájl - + Overwrite existing Meglévő felülírása - + Password Jelszó - + Password for the file Jelszó a fájlhoz - + Passwords don't match! A jelszavak nem egyeznek! - + Passwords match! A jelszavak egyeznek! - + Repeated Password for the file Megismételt jelszó a fájlhoz - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Itt tudsz tokeneket importálni egy fájlból. Írd be a fájl helyét, és az exportáláskor használt jelszót. Húzd balra az importálás indításához. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Itt tudsz tokeneket exportálni egy fájlba. Az exportált fájl AES-256-CBC és Base64 kódolással lesz ellátva. Válassz egy erős jelszót, a fájl a fiókjaidoz létrehozandó tokenehez tartozó jelszavakat fogja tartalmazni. Húzd balra az exportálás indításához. - + To view the content of the export file outside of SailOTP use the following openssl command: Az exportfájl tartalmának a SailOTP-n kívüli megtekintéséhez használd a következő openssl parancsokat: - + Error writing to file Hiba a fájlba íráskor - + Token Database exported to Tokenadatbázis exportálva ide: - + Could not encrypt tokens. Error: A tokenek nem titkosíthatók. Hiba: - + Could not read tokens from Database A tokenek nem olvashatók az adatbázisból - + Tokens imported from Tokenek importálva innen: - + Unable to decrypt file, did you use the right password? Nem lehet dekódolni a fájlt, a helyes jelszót használtad? - + Could not read from file Nem olvasható a fájlból diff --git a/translations/harbour-sailotp-it.ts b/translations/harbour-sailotp-it.ts index f3f4a4a..79b7b6e 100644 --- a/translations/harbour-sailotp-it.ts +++ b/translations/harbour-sailotp-it.ts @@ -188,109 +188,109 @@ Il file passato non esiste! - - + + Export Esporta - - + + Import Importa - + Filename Nome file - + File to import File da importare - + File to export File da esportare - + Overwrite existing Sovrascrivi esistente - + Password Password - + Password for the file Password per il file - + Passwords don't match! Le password non corrispondono! - + Passwords match! Le password corrispondono! - + Repeated Password for the file Password Ripetuta per il file - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Da qua puoi Importare i Token da un file. Inserisci la posizione del file e la password usata nell'esportazione. Scorri a sinistra per iniziare l'importazione. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Da qua puoi Esportare i Token su un file. Il file esportato sarà criptato con AES-256-CBC e codificato Base64. Scegli una password forte, il file conterrà i segreti usati per generare i Token per i tuoi account. Scorri a sinistra per iniziare l'esportazione. - + To view the content of the export file outside of SailOTP use the following openssl command: Per vedere il contenuto del file esportato al di fuori di SailORP usa il seguente comando openssl: - + Error writing to file Errore in scrittura del file - + Token Database exported to Database dei Toen esportato su - + Could not encrypt tokens. Error: Impossibile criptare i token. Errore: - + Could not read tokens from Database Impossibile leggere i token dal Database - + Tokens imported from Token importati da - + Unable to decrypt file, did you use the right password? Non ho potuto decrittare il file, hai scritto la password correttamente? - + Could not read from file Impossibile leggere dal file diff --git a/translations/harbour-sailotp-nl.ts b/translations/harbour-sailotp-nl.ts index 643f0a5..3d6d38b 100644 --- a/translations/harbour-sailotp-nl.ts +++ b/translations/harbour-sailotp-nl.ts @@ -188,109 +188,109 @@ Bestand bestaat niet! - - + + Export Exporteer - - + + Import Importeer - + Filename Bestandsnaam - + File to import Bestand om te importeren - + File to export Bestand om te exporteren - + Overwrite existing Bestaand bestand overschrijven - + Password Wachtwoord - + Password for the file Wachtwoord voor het bestand - + Passwords don't match! Wachtwoorden komen niet overeen! - + Passwords match! Wachtwoorden komen overeen! - + Repeated Password for the file Herhaal wachtwoord voor het bestand - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Hier kunt u tokens uit een bestand importeren. Geef de bestandslocatie en het wachtwoord dat u bij export hebt gebruikt op. Veeg naar links om het importeren te starten. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Hier kun je tokens naar een bestand exporteren. Het geexporteerde bestand wordt versleuteld met AES-256-CBC en is Base64-gecodeerd. Kies een sterk wachtwoord, het bestand bevat de geheimen die worden gebruikt om de tokens voor uw accounts te genereren. Veeg naar links om de export te starten. - + To view the content of the export file outside of SailOTP use the following openssl command: Als u de inhoud van het exportbestand buiten SailOTP wilt bekijken, gebruikt u de volgende OpenSSL-opdracht: - + Error writing to file Fout bij schrijven naar bestand - + Token Database exported to Token Database geexporteerd naar - + Could not encrypt tokens. Error: Kan tokens niet coderen. Fout: - + Could not read tokens from Database Kan geen tokens uit database lezen - + Tokens imported from Tokens geimporteerd uit - + Unable to decrypt file, did you use the right password? Kan het bestand niet ontsleutelen, heeft u het juiste wachtwoord gebruikt? - + Could not read from file Kan niet lezen uit bestand diff --git a/translations/harbour-sailotp-pt_BR.ts b/translations/harbour-sailotp-pt_BR.ts index 3070f68..b0f36f8 100644 --- a/translations/harbour-sailotp-pt_BR.ts +++ b/translations/harbour-sailotp-pt_BR.ts @@ -188,109 +188,109 @@ Não foi possíve encontrar o arquivo! - - + + Export Exportar - - + + Import Importar - + Filename Nome do arquivo - + File to import Arquivo para importar - + File to export Arquivo para exportar - + Overwrite existing Sobrescrever existente - + Password Senha - + Password for the file Insira a senha do arquivo aqui - + Passwords don't match! As senhas não coincidem! - + Passwords match! Senha correta - + Repeated Password for the file Confirme a senha do arquivo aqui - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Importe Tokens salvos de um arquivo. Insira a localização do arquivo e a senha usada durante a exportação. Deslize para a esquerda para iniciar a importação. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Exporte os Tokens para um arquivo. O arquivo exportado será criptografado com AES-256-CBC e codificado em Base64. Escolha uma senha forte pois o arquivo conterá todos os segredos usados para gerar os Tokens disponíveis. Deslize para a esquerda para iniciar o processo. - + To view the content of the export file outside of SailOTP use the following openssl command: Para visualizar o conteúdo do arquivo expotado fora do SailOTP use o seguinte comando openssl: - + Error writing to file Não foi possível escrever no arquivo - + Token Database exported to Base de dados dos Tokens exportada para - + Could not encrypt tokens. Error: Não foi possível criptografar Tokens. Erro: - + Could not read tokens from Database Não foi possível ler Tokens da base de dados - + Tokens imported from Tokens importados de - + Unable to decrypt file, did you use the right password? Não foi possível decriptografar arquivo, por favor cheque a senha. - + Could not read from file Não foi possível ler arquivo diff --git a/translations/harbour-sailotp-ru.ts b/translations/harbour-sailotp-ru.ts index fba272d..15113ee 100644 --- a/translations/harbour-sailotp-ru.ts +++ b/translations/harbour-sailotp-ru.ts @@ -188,110 +188,110 @@ Данный файл не существует! - - + + Export Экспорт - - + + Import Импорт - + Filename Имя файла - + File to import Файл для импорта - + File to export Файл для экспорта - + Overwrite existing Перезаписать существующий - + Password Пароль - + Password for the file Пароль для файла - + Passwords don't match! Пароли не совпадают! - + Passwords match! Пароли совпадают! - + Repeated Password for the file Повторный пароль для файла - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Здесь можно импортировать токены из файла. Введите путь к файлу и пароль, использованный при экспорте. Потяните влево чтобы начать импорт. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Здесь можно экспортировать токены в файл. Экспортированный файл будет зашифрован с использованием AES-256-CBC и кодирован в Base64. Выберите сильный пароль — файл будет содержать секреты, использованные для генерации токенов для Ваших аккаунтов. Потяните влево чтобы начать экспорт. - + To view the content of the export file outside of SailOTP use the following openssl command: Translated using Google Translate Чтобы просмотреть содержимое файла экспорта за пределами SailOTP, используйте следующую команду openssl: - + Error writing to file Ошибка при записи в файл - + Token Database exported to База данных токенов экспортирована в - + Could not encrypt tokens. Error: Не удалось зашифровать токены. Ошибка: - + Could not read tokens from Database Не удалось прочесть токены из базы данных - + Tokens imported from Токены импортированы из - + Unable to decrypt file, did you use the right password? Не удалось расшифровать файл. Был ли введен правильный пароль? - + Could not read from file Не удалось прочесть из файла diff --git a/translations/harbour-sailotp-sv.ts b/translations/harbour-sailotp-sv.ts index c4f5050..5987bba 100644 --- a/translations/harbour-sailotp-sv.ts +++ b/translations/harbour-sailotp-sv.ts @@ -188,109 +188,109 @@ Angiven fil finns inte! - - + + Export Exportera - - + + Import Importera - + Filename Filnamn - + File to import Fil att importera - + File to export Fil att exportera - + Overwrite existing Skriv över befintlig - + Password Lösenord - + Password for the file Lösenord för filen - + Passwords don't match! Lösenorden stämmer inte! - + Passwords match! Lösenorden stämmer! - + Repeated Password for the file Upprepat lösenordet för filen - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. Här kan du importera Token från en fil. Ange filens sökväg och lösenordet du angav vid exporten. Svep åt vänster för att starta importen. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. Här kan du exportera Token till en fil. Den exporterade filen kommer att krypteras med AES-256-CBC och Base64. Välj ett starkt lösenord, filen kommer att innehålla hemligheterna som användes för att generera Token för ditt konto. Svep åt vänster för att starta exporten. - + To view the content of the export file outside of SailOTP use the following openssl command: För att visa innehållet i exportfilen utanför SailOTP, använder du följande openssl-kommando: - + Error writing to file Fel vid skrivning till fil - + Token Database exported to Token-databas exporterad till - + Could not encrypt tokens. Error: Kunde inte kryptera token. Fel: - + Could not read tokens from Database Kunde inte läsa token från databasen - + Tokens imported from Token importerade från - + Unable to decrypt file, did you use the right password? Kunde inte dekryptera filen. Angav du rätt lösenord? - + Could not read from file Kunde inte läsa från fil diff --git a/translations/harbour-sailotp-zh_CN.ts b/translations/harbour-sailotp-zh_CN.ts index 2ec7937..6d2d6e0 100644 --- a/translations/harbour-sailotp-zh_CN.ts +++ b/translations/harbour-sailotp-zh_CN.ts @@ -188,109 +188,109 @@ 选择的文件不存在 - - + + Export 导出 - - + + Import 导入 - + Filename 文件名 - + File to import - + File to export 要导出的文件 - + Overwrite existing 覆盖已存在 - + Password 密码 - + Password for the file 文件加密的密码 - + Passwords don't match! 密码不匹配 - + Passwords match! 密码匹配 - + Repeated Password for the file 替换文件的密码 - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. 在这里,你可以从文件导入令牌。输入你在导出时使用的文件位置和密码,向左拉开始导入 - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. 在这里,您可以将令牌导出到文件。导出的文件将使用AES-256-CBC和Base64编码进行加密。选择一个强密码,该文件将包含用于为你的帐户生成令牌的密钥。向左拉开始导出 - + To view the content of the export file outside of SailOTP use the following openssl command: 在SailfOTP外面查看导出的文件,使用下面的openssl命令: - + Error writing to file 写入文件错误 - + Token Database exported to 令牌数据导出到 - + Could not encrypt tokens. Error: 不能加密令牌,错误: - + Could not read tokens from Database 不能从数据库中读取令牌 - + Tokens imported from 令牌已从文件导入 - + Unable to decrypt file, did you use the right password? 不能加密文件,确定使用了正确的密码? - + Could not read from file 不能从文件读取 diff --git a/translations/harbour-sailotp.ts b/translations/harbour-sailotp.ts index fa7dc66..3b8afa2 100644 --- a/translations/harbour-sailotp.ts +++ b/translations/harbour-sailotp.ts @@ -188,109 +188,109 @@ - - + + Export - - + + Import - + Filename - + File to import - + File to export - + Overwrite existing - + Password - + Password for the file - + Passwords don't match! - + Passwords match! - + Repeated Password for the file - + Here you can Import Tokens from a file. Put in the file location and the password you used on export. Pull left to start the import. - + Here you can export Tokens to a file. The exported file will be encrypted with AES-256-CBC and Base64 encoded. Choose a strong password, the file will contain the secrets used to generate the Tokens for your accounts. Pull left to start the export. - + To view the content of the export file outside of SailOTP use the following openssl command: - + Error writing to file - + Token Database exported to - + Could not encrypt tokens. Error: - + Could not read tokens from Database - + Tokens imported from - + Unable to decrypt file, did you use the right password? - + Could not read from file