mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Protocol rewrite with tweetnacl-js
This commit is contained in:
parent
cbd1fc96a3
commit
dbef129ba3
5 changed files with 509 additions and 184 deletions
198
README.md
198
README.md
|
|
@ -16,4 +16,202 @@ GNU General Public License for more details.
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
```
|
||||
|
||||
## Protocol
|
||||
|
||||
Transmitting messages between KeePassXC and chromeKeePassXC is totally rewritten. This is still under development.
|
||||
Now the requests are encrypted by [TweetNaCl.js](https://github.com/dchest/tweetnacl-js) box method and does the following:
|
||||
|
||||
1. chromeKeePassXC generates a key pair (with public and secret key) and transfers the public key to KeePassXC
|
||||
2. When KeePassXC receives the public key it generates its own key pair and transfers the public key to chromeKeePassXC
|
||||
3. All messages (excluding get-databasehash) are now encrypted.
|
||||
4. When chromeKeePassXC sends a message it is encrypted with KeePassXC's public key, a random generated nonce and chromeKeePassXC's secret key.
|
||||
5. When KeePassXC sends a message it is encrypted with chromeKeePassXC's public key etc.
|
||||
|
||||
Encrypted messages are built with these JSON parameters:
|
||||
- action - `test-associate`, `associate`, `get-logins`, `get-logins-count, `set-login`...
|
||||
- message - Encrypted message, base64 encoded
|
||||
- nonce - 24 bytes long random data, base64 encoded. This must be the same when responding to a request.
|
||||
|
||||
### get-databasehash
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-databasehash"
|
||||
}
|
||||
```
|
||||
|
||||
Response (success):
|
||||
```javascript
|
||||
{
|
||||
"action": "hash",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.1.2"
|
||||
}
|
||||
```
|
||||
|
||||
### associate
|
||||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "associate"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "associate",
|
||||
"message": encryptedMessage
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.1.2",
|
||||
"success": "true",
|
||||
"id": "testclient",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
### test-associate
|
||||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "test-associate"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "test-associate",
|
||||
"message": encryptedMessage
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"version": "2.1.2",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"id": "testclient",
|
||||
"success": "true"
|
||||
}
|
||||
```
|
||||
|
||||
### generate-password
|
||||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "generate-password"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "generate-password",
|
||||
"message": encryptedMessage
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"version": "2.1.2",
|
||||
"entries": [
|
||||
{
|
||||
"login": 144,
|
||||
"password": "testclientpassword"
|
||||
}
|
||||
],
|
||||
"success": "true",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
### get-logins
|
||||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-logins",
|
||||
"url": "<snip>",
|
||||
"submitUrl": optional
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-logins",
|
||||
"message": encryptedMessage
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"count": "2",
|
||||
"entries" : [
|
||||
{
|
||||
"login": "user1",
|
||||
"name": "user1",
|
||||
"password": "passwd1"
|
||||
},
|
||||
{
|
||||
"login": "user2",
|
||||
"name": "user2",
|
||||
"password": "passwd2"
|
||||
}],
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"success": "true",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.1.2"
|
||||
}
|
||||
```
|
||||
|
||||
### set-login
|
||||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "set-login",
|
||||
"url": "<snip>",
|
||||
"submitUrl": "<snip>",
|
||||
"id": "testclient",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"login": "user1",
|
||||
"password": "passwd1"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "set-login",
|
||||
"message": encryptedMessage
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"count": null,
|
||||
"entries" : null,
|
||||
"error": "",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"success": "true",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.1.2"
|
||||
}
|
||||
```
|
||||
|
|
@ -6,7 +6,9 @@ page.initSettings();
|
|||
page.initOpenedTabs();
|
||||
// initial connection with KeePassXC
|
||||
keepass.connectToNative();
|
||||
keepass.generateNewKeyPair();
|
||||
keepass.getDatabaseHash(null);
|
||||
keepass.changePublicKeys();
|
||||
// set initial tab-ID
|
||||
chrome.tabs.query({"active": true, "windowId": chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
|
||||
if (tabs.length === 0)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
var keepass = {};
|
||||
|
||||
keepass.associated = {"value": false, "hash": null};
|
||||
keepass.keyPair = {publicKey: null, secretKey: null};
|
||||
keepass.serverPublicKey = "";
|
||||
keepass.isConnected = false;
|
||||
keepass.isDatabaseClosed = false;
|
||||
keepass.isKeePassXCAvailable = false;
|
||||
keepass.useSecretBox = false;
|
||||
keepass.useBox = false;
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
keepass.currentKeePassXC = {"version": 0, "versionParsed": 0};
|
||||
keepass.latestKeePassXC = (typeof(localStorage.latestKeePassXC) == 'undefined') ? {"version": 0, "versionParsed": 0, "lastChecked": null} : JSON.parse(localStorage.latestKeePassXC);
|
||||
keepass.requiredKeePassXC = 212;
|
||||
keepass.nativeHostName = "com.varjolintu.chromekeepassxc";
|
||||
keepass.nativePort = null;
|
||||
keepass.keySize = 8;
|
||||
keepass.keySize = 24;
|
||||
keepass.latestVersionUrl = "https://raw.githubusercontent.com/keepassxreboot/keepassxc/develop/CHANGELOG";
|
||||
keepass.cacheTimeout = 30 * 1000; // milliseconds
|
||||
keepass.databaseHash = "no-hash"; //no-hash = keepasshttp is too old and does not return a hash value
|
||||
|
|
@ -26,6 +28,7 @@ keepass.addCredentials = function(callback, tab, username, password, url) {
|
|||
keepass.updateCredentials(callback, tab, null, username, password, url);
|
||||
}
|
||||
|
||||
// Not tested
|
||||
keepass.updateCredentials = function(callback, tab, entryId, username, password, url) {
|
||||
page.debug("keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})", tab.id, entryId, username, url);
|
||||
|
||||
|
|
@ -40,42 +43,53 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password,
|
|||
}
|
||||
|
||||
// build request
|
||||
var request = {
|
||||
RequestType: "set-login"
|
||||
var messageData = {
|
||||
action: "set-login"
|
||||
};
|
||||
var verifier = keepass.setVerifier(request);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
var iv = request.Nonce;
|
||||
|
||||
var key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
var nonce = nacl.randomBytes(keepass.keySize);
|
||||
|
||||
request.Login = keepass.encrypt(nacl.util.encode_UTF8(username), key, iv);
|
||||
messageData.login = username;
|
||||
messageData.password = password;
|
||||
messageData.url = url;
|
||||
messageData.submitUrl = url;
|
||||
|
||||
request.Password = keepass.encrypt(nacl.util.encode_UTF8(password), key, iv);
|
||||
request.Url = keepass.encrypt(url, key, iv);
|
||||
request.SubmitUrl = keepass.encrypt(url, key, iv);
|
||||
|
||||
if(entryId) {
|
||||
request.Uuid = keepass.encrypt(entryId, key, iv);
|
||||
if (entryId) {
|
||||
messageData.uuid = entryId;
|
||||
}
|
||||
|
||||
// send request
|
||||
var result = keepass.send(request);
|
||||
var status = result[0];
|
||||
var response = result[1];
|
||||
var request = {
|
||||
action: "set-login",
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
//nonce: keepass.b64e(nonce)
|
||||
nonce: "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q" // Hard-coded test nonce
|
||||
};
|
||||
|
||||
// verify response
|
||||
var code = "error";
|
||||
if(keepass.checkStatus(status, tab)) {
|
||||
var r = JSON.parse(response);
|
||||
if (keepass.verifyResponse(r, key, id)) {
|
||||
code = "success";
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "set-login", function(response) {
|
||||
if (response.message && response.nonce) {
|
||||
var res = keepass.decrypt(response.message, response.nonce);
|
||||
if (res == false)
|
||||
{
|
||||
console.log("Failed to decrypt message");
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = nacl.util.encodeUTF8(res);
|
||||
var parsed = JSON.parse(message);
|
||||
var code = "error";
|
||||
console.log(parsed);
|
||||
|
||||
if (keepass.verifyResponse(parsed, response.nonce)) {
|
||||
code = "success";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
code = "error";
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
keepass.nativePort.postMessage(request);
|
||||
callback(code);
|
||||
}
|
||||
|
||||
|
|
@ -97,43 +111,59 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall
|
|||
}
|
||||
|
||||
var entries = [];
|
||||
message = {
|
||||
"action": "get-logins",
|
||||
"url": url
|
||||
var key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
var nonce = nacl.randomBytes(keepass.keySize);
|
||||
|
||||
var messageData = {
|
||||
action: "get-logins",
|
||||
url: url
|
||||
};
|
||||
|
||||
var verifier = keepass.setVerifier(message);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
var iv = message.nonce;
|
||||
var entries = [];
|
||||
if (submiturl) {
|
||||
messageData.submitUrl = submiturl;
|
||||
}
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "get-logins-reply", function(response) {
|
||||
if (response) {
|
||||
keepass.setcurrentKeePassXCVersion(response.version);
|
||||
var request = {
|
||||
action: "get-logins",
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
//nonce: keepass.b64e(nonce)
|
||||
nonce: "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q" // Hard-coded test nonce
|
||||
};
|
||||
|
||||
if (keepass.verifyResponse(response, key, id)) {
|
||||
var rIv = response.nonce;
|
||||
for (var i = 0; i < response.entries.length; i++) {
|
||||
keepass.decryptEntry(response.entries[i], key, rIv);
|
||||
}
|
||||
entries = response.entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
if(entries.length == 0) {
|
||||
//questionmark-icon is not triggered, so we have to trigger for the normal symbol
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
callback(entries);
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "get-logins", function(response) {
|
||||
if (response.message && response.nonce) {
|
||||
var res = keepass.decrypt(response.message, response.nonce);
|
||||
if (res == false)
|
||||
{
|
||||
console.log("Failed to decrypt message");
|
||||
}
|
||||
else {
|
||||
console.log("RetrieveCredentials for " + url + " rejected");
|
||||
else
|
||||
{
|
||||
var message = nacl.util.encodeUTF8(res);
|
||||
var parsed = JSON.parse(message);
|
||||
console.log(parsed);
|
||||
|
||||
keepass.setcurrentKeePassXCVersion(parsed.version);
|
||||
|
||||
if (keepass.verifyResponse(parsed, response.nonce)) {
|
||||
entries = parsed.entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
if (entries.length == 0) {
|
||||
//questionmark-icon is not triggered, so we have to trigger for the normal symbol
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
callback(entries);
|
||||
}
|
||||
else {
|
||||
console.log("RetrieveCredentials for " + url + " rejected");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
keepass.nativePort.postMessage(request);
|
||||
page.debug("keepass.retrieveCredentials() => entries.length = {1}", entries.length);
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +171,7 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall
|
|||
keepass.handleReply = function (msg) {
|
||||
// Specific callback handling. Needed?
|
||||
/*var reply;
|
||||
if (msg.action == "generate-reply") {
|
||||
if (msg.action == "generate-password") {
|
||||
|
||||
}
|
||||
else {
|
||||
|
|
@ -185,36 +215,54 @@ keepass.generatePassword = function (callback, tab, forceCallback) {
|
|||
}
|
||||
|
||||
var passwords = [];
|
||||
message = { "action": "generate-password" };
|
||||
var verifier = keepass.setVerifier(message);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
var key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
var nonce = nacl.randomBytes(keepass.keySize);
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "generate-reply", function(response) {
|
||||
console.log("Handling generate-reply");
|
||||
keepass.setcurrentKeePassXCVersion(response.version);
|
||||
var passwords = [];
|
||||
var messageData = {
|
||||
action: "generate-password"
|
||||
};
|
||||
|
||||
if (keepass.verifyResponse(response, key, id)) {
|
||||
var rIv = response.nonce;
|
||||
var request = {
|
||||
action: "generate-password",
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
//nonce: keepass.b64e(nonce)
|
||||
nonce: "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q" // Hard-coded test nonce
|
||||
};
|
||||
|
||||
if(response.entries) {
|
||||
for (var i = 0; i < response.entries.length; i++) {
|
||||
keepass.decryptEntry(response.entries[i], key, rIv);
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "generate-password", function(response) {
|
||||
if (response.message && response.nonce) {
|
||||
var res = keepass.decrypt(response.message, response.nonce);
|
||||
if (res == false)
|
||||
{
|
||||
console.log("Failed to decrypt message");
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = nacl.util.encodeUTF8(res);
|
||||
var parsed = JSON.parse(message);
|
||||
console.log(parsed);
|
||||
|
||||
keepass.setcurrentKeePassXCVersion(parsed.version);
|
||||
if (keepass.verifyResponse(parsed, response.nonce)) {
|
||||
var rIv = response.nonce;
|
||||
|
||||
// var response = JSON.stringify({ Login: (msg.password.length * 8), Password: msg.password });
|
||||
if(parsed.entries) {
|
||||
passwords = parsed.entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
}
|
||||
else {
|
||||
console.log("No entries returned. Is KeePassXC up-to-date?");
|
||||
}
|
||||
}
|
||||
passwords = response.entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
}
|
||||
else {
|
||||
console.log("No entries returned. Is KeePassHttp up-to-date?");
|
||||
else {
|
||||
console.log("GeneratePassword rejected");
|
||||
}
|
||||
callback(passwords);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("GeneratePassword rejected");
|
||||
}
|
||||
callback(passwords);
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
keepass.nativePort.postMessage(request);
|
||||
}
|
||||
|
||||
keepass.copyPassword = function(callback, tab, password) {
|
||||
|
|
@ -248,37 +296,52 @@ keepass.associate = function(callback, tab) {
|
|||
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
||||
var rawKey = nacl.randomBytes(keepass.keySize * 2);
|
||||
//var rawKey = [41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56]; // This is just for testing with the test client. KSorLC0uLzAxMjM0NTY3OA== )*+,-./012345678
|
||||
//console.log(rawKey);
|
||||
var key = keepass.b64e(rawKey);
|
||||
var key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
var nonce = nacl.randomBytes(keepass.keySize);
|
||||
|
||||
var messageData = {
|
||||
action: "associate"
|
||||
};
|
||||
|
||||
var request = {
|
||||
action: "associate",
|
||||
key: key
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
//nonce: keepass.b64e(nonce)
|
||||
nonce: "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q" // Hard-coded test nonce
|
||||
};
|
||||
|
||||
keepass.setVerifier(request, key);
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "associate", function(response) {
|
||||
if (response.message && response.nonce) {
|
||||
var res = keepass.decrypt(response.message, response.nonce);
|
||||
if (res == false)
|
||||
{
|
||||
console.log("Failed to decrypt message");
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = nacl.util.encodeUTF8(res);
|
||||
var parsed = JSON.parse(message);
|
||||
console.log(parsed);
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "associate-reply", function(response) {
|
||||
if (response.version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": response.version,
|
||||
"versionParsed": parseInt(response.version.replace(/\./g,""))}
|
||||
;
|
||||
}
|
||||
if (parsed.version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": parsed.version,
|
||||
"versionParsed": parseInt(parsed.version.replace(/\./g,""))};
|
||||
}
|
||||
|
||||
var id = response.id;
|
||||
if(!keepass.verifyResponse(response, key)) {
|
||||
page.tabs[tab.id].errorMessage = "KeePassXC association failed, try again.";
|
||||
}
|
||||
else {
|
||||
keepass.setCryptoKey(id, key);
|
||||
keepass.associated.value = true;
|
||||
keepass.associated.hash = response.hash || 0;
|
||||
}
|
||||
var id = parsed.id;
|
||||
if(!keepass.verifyResponse(parsed, response.nonce)) {
|
||||
page.tabs[tab.id].errorMessage = "KeePassXC association failed, try again.";
|
||||
}
|
||||
else {
|
||||
keepass.setCryptoKey(id, key);
|
||||
keepass.associated.value = true;
|
||||
keepass.associated.hash = parsed.hash || 0;
|
||||
}
|
||||
|
||||
browserAction.show(callback, tab);
|
||||
browserAction.show(callback, tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
keepass.nativePort.postMessage(request);
|
||||
|
|
@ -295,46 +358,59 @@ keepass.testAssociation = function (tab, triggerUnlock) {
|
|||
return true;
|
||||
}
|
||||
|
||||
var message = {
|
||||
var key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
var nonce = nacl.randomBytes(keepass.keySize);
|
||||
|
||||
var messageData = {
|
||||
"action": "test-associate",
|
||||
};
|
||||
var verifier = keepass.setVerifier(message);
|
||||
|
||||
var request = {
|
||||
action: "test-associate",
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
//nonce: keepass.b64e(nonce)
|
||||
nonce: "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q" // Hard-coded test nonce
|
||||
};
|
||||
|
||||
if(!verifier) {
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
return false;
|
||||
}
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "test-associate", function(response) {
|
||||
if (response.message && response.nonce) {
|
||||
var res = keepass.decrypt(response.message, response.nonce);
|
||||
if (res == false)
|
||||
{
|
||||
console.log("Failed to decrypt message");
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "test-associate-reply", function(response) {
|
||||
if (response) {
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
|
||||
if(response.version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": response.version,
|
||||
"versionParsed": parseInt(response.version.replace(/\./g,""))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = nacl.util.encodeUTF8(res);
|
||||
var parsed = JSON.parse(message);
|
||||
console.log(parsed);
|
||||
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
if(!keepass.verifyResponse(response, key, id)) {
|
||||
var hash = response.hash || 0;
|
||||
keepass.deleteKey(hash);
|
||||
keepass.isEncryptionKeyUnrecognized = true;
|
||||
console.log("Encryption key is not recognized!");
|
||||
page.tabs[tab.id].errorMessage = "Encryption key is not recognized.";
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
}
|
||||
else if(!keepass.isAssociated()) {
|
||||
console.log("Association was not successful");
|
||||
page.tabs[tab.id].errorMessage = "Association was not successful.";
|
||||
if (parsed.version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": parsed.version,
|
||||
"versionParsed": parseInt(parsed.version.replace(/\./g,""))};
|
||||
}
|
||||
|
||||
var id = parsed.id;
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
if(!keepass.verifyResponse(parsed, response.nonce)) {
|
||||
var hash = response.hash || 0;
|
||||
keepass.deleteKey(hash);
|
||||
keepass.isEncryptionKeyUnrecognized = true;
|
||||
console.log("Encryption key is not recognized!");
|
||||
page.tabs[tab.id].errorMessage = "Encryption key is not recognized.";
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
}
|
||||
else if(!keepass.isAssociated()) {
|
||||
console.log("Association was not successful");
|
||||
page.tabs[tab.id].errorMessage = "Association was not successful.";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
keepass.nativePort.postMessage(request);
|
||||
|
||||
return keepass.isAssociated();
|
||||
}
|
||||
|
|
@ -345,8 +421,8 @@ keepass.getDatabaseHash = function (callback, tab, triggerUnlock) {
|
|||
}
|
||||
|
||||
message = { "action": "get-databasehash" };
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "hash-reply", function(response) {
|
||||
console.log("hash-reply received: "+ response.hash);
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "hash", function(response) {
|
||||
console.log("hash reply received: "+ response.hash);
|
||||
var oldDatabaseHash = keepass.databaseHash;
|
||||
keepass.setcurrentKeePassXCVersion(response.version);
|
||||
keepass.databaseHash = response.hash || "no-hash";
|
||||
|
|
@ -362,6 +438,55 @@ keepass.getDatabaseHash = function (callback, tab, triggerUnlock) {
|
|||
keepass.nativePort.postMessage(message);
|
||||
}
|
||||
|
||||
keepass.changePublicKeys = function() {
|
||||
if (!keepass.isConnected || !keepass.databaseHash || keepass.databaseHash !== "no-hash") {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
var nonce = nacl.randomBytes(keepass.keySize);
|
||||
nonce = keepass.b64e(nonce);
|
||||
|
||||
message = {
|
||||
"action": "change-public-keys",
|
||||
"publicKey": key,
|
||||
"nonce": nonce
|
||||
}
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "change-public-keys", function(response) {
|
||||
console.log("change-public-keys reply received");
|
||||
if(response.version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": response.version,
|
||||
"versionParsed": parseInt(response.version.replace(/\./g,""))
|
||||
};
|
||||
}
|
||||
|
||||
var id = response.id;
|
||||
if(!keepass.verifyKeyResponse(response, key, nonce)) {
|
||||
console.log("Error");
|
||||
}
|
||||
else {
|
||||
console.log("Server public key: " + keepass.b64e(keepass.serverPublicKey));
|
||||
}
|
||||
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
}
|
||||
|
||||
keepass.generateNewKeyPair = function() {
|
||||
if (keepass.keyPair.publicKey !== null && keepass.keyPair.secretKey !== null)
|
||||
return;
|
||||
|
||||
// For debugging (server public: w5vx7v7rPv/SWnyeyeSztvdGMinYr0q+bBwLMTeDrzo= server secret: 8AUkW7LBxx0Na32nWPVLq8U8xOCeC0Xya1NTcRrd7f4=)
|
||||
keepass.keyPair.publicKey = keepass.b64d("dIPmlz7CutTJwb4c7pgGuflE2xfISVpI0YAyeyXHhU8=");
|
||||
keepass.keyPair.secretKey = keepass.b64d("XjrUmGhhECdnSbRZbfAhb8jqGB2uK50d/HPRJG/OcFk=");
|
||||
|
||||
// The real key pair
|
||||
//keepass.keyPair = nacl.box.keyPair();
|
||||
console.log(keepass.b64e(keepass.keyPair.publicKey) + " " + keepass.b64e(keepass.keyPair.secretKey));
|
||||
}
|
||||
|
||||
keepass.isConfigured = function() {
|
||||
if(typeof(keepass.databaseHash) == "undefined") {
|
||||
keepass.getDatabaseHash();
|
||||
|
|
@ -412,9 +537,6 @@ keepass.checkStatus = function (status, tab) {
|
|||
|
||||
keepass.convertKeyToKeyRing = function() {
|
||||
if(keepass.keyId in localStorage && keepass.keyBody in localStorage && !("keyRing" in localStorage)) {
|
||||
//var hash = keepass.getDatabaseHash(null);
|
||||
//keepass.saveKey(hash, localStorage[keepass.keyId], localStorage[keepass.keyBody]);
|
||||
|
||||
keepass.getDatabaseHash(function(hash) {
|
||||
keepass.saveKey(hash, localStorage[keepass.keyId], localStorage[keepass.keyBody]);
|
||||
}, null);
|
||||
|
|
@ -430,7 +552,8 @@ keepass.saveKey = function(hash, id, key) {
|
|||
if(!(hash in keepass.keyRing)) {
|
||||
keepass.keyRing[hash] = {
|
||||
"id": id,
|
||||
"key": key,
|
||||
//"key": key,
|
||||
"hash": hash,
|
||||
"icon": "blue",
|
||||
"created": new Date(),
|
||||
"last-used": new Date()
|
||||
|
|
@ -438,7 +561,8 @@ keepass.saveKey = function(hash, id, key) {
|
|||
}
|
||||
else {
|
||||
keepass.keyRing[hash].id = id;
|
||||
keepass.keyRing[hash].key = key;
|
||||
//keepass.keyRing[hash].key = key;
|
||||
keepass.keyRing[hash].hash = hash;
|
||||
}
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
|
|
@ -557,17 +681,37 @@ keepass.setVerifier = function(request, inputKey) {
|
|||
request.id = id;
|
||||
}
|
||||
|
||||
var nonce = nacl.randomBytes(keepass.keySize * 2);
|
||||
var nonce = nacl.randomBytes(keepass.keySize);
|
||||
request.nonce = keepass.b64e(nonce);
|
||||
request.verifier = keepass.encrypt(request.nonce, key, request.nonce);
|
||||
|
||||
var test = keepass.encrypt("Aeh9maerCjE5v5V8Tz2YxA==", key, "Aeh9maerCjE5v5V8Tz2YxA==");
|
||||
console.log(test);
|
||||
request.publicKey = key;
|
||||
|
||||
return [id, key];
|
||||
}
|
||||
|
||||
keepass.verifyResponse = function(response, key, id) {
|
||||
keepass.verifyKeyResponse = function(response, key, nonce) {
|
||||
if (!response.success || !response.publicKey) {
|
||||
keepass.associated.hash = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var reply = false;
|
||||
|
||||
var respnonce = keepass.b64d(response.nonce);
|
||||
if (keepass.b64d(nonce).length !== nacl.secretbox.nonceLength)
|
||||
return false;
|
||||
|
||||
reply = (response.nonce == nonce);
|
||||
|
||||
if (response.publicKey) {
|
||||
keepass.serverPublicKey = keepass.b64d(response.publicKey);
|
||||
reply = true;
|
||||
}
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
keepass.verifyResponse = function(response, nonce, id) {
|
||||
keepass.associated.value = response.success;
|
||||
if (!response.success) {
|
||||
keepass.associated.hash = null;
|
||||
|
|
@ -576,10 +720,10 @@ keepass.verifyResponse = function(response, key, id) {
|
|||
|
||||
keepass.associated.hash = keepass.databaseHash;
|
||||
|
||||
var nonce = response.nonce;
|
||||
var value = keepass.decrypt(response.verifier, key, nonce, true);
|
||||
if (keepass.b64d(response.nonce).length !== nacl.secretbox.nonceLength)
|
||||
return false;
|
||||
|
||||
keepass.associated.value = (value == nonce);
|
||||
keepass.associated.value = (response.nonce == nonce);
|
||||
|
||||
if(id) {
|
||||
keepass.associated.value = (keepass.associated.value && id == response.id);
|
||||
|
|
@ -592,12 +736,10 @@ keepass.verifyResponse = function(response, key, id) {
|
|||
}
|
||||
|
||||
keepass.b64e = function(d) {
|
||||
//return btoa(keepass.to_s(d));
|
||||
return nacl.util.encodeBase64(d);
|
||||
}
|
||||
|
||||
keepass.b64d = function(d) {
|
||||
//return keepass.to_b(atob(d));
|
||||
return nacl.util.decodeBase64(d);
|
||||
}
|
||||
|
||||
|
|
@ -610,7 +752,8 @@ keepass.getCryptoKey = function() {
|
|||
var key = null;
|
||||
|
||||
if(id) {
|
||||
key = keepass.keyRing[keepass.databaseHash].key;
|
||||
//key = keepass.keyRing[keepass.databaseHash].key;
|
||||
key = keepass.b64e(keepass.keyPair.publicKey);
|
||||
}
|
||||
|
||||
return key ? [id, key] : null;
|
||||
|
|
@ -620,31 +763,14 @@ keepass.setCryptoKey = function(id, key) {
|
|||
keepass.saveKey(keepass.databaseHash, id, key);
|
||||
}
|
||||
|
||||
keepass.encrypt = function(input, key, nonce) {
|
||||
return keepass.b64e(slowAES.encrypt(keepass.to_b(input), slowAES.modeOfOperation.CBC, keepass.b64d(key), keepass.b64d(nonce)));
|
||||
//return keepass.b64e(nacl.secretbox(keepass.to_b(input), keepass.b64d(nonce), keepass.b64d(key)));
|
||||
keepass.encrypt = function(input, nonce) {
|
||||
var messageData = nacl.util.decodeUTF8(JSON.stringify(input));
|
||||
var message = nacl.box(messageData, nonce, keepass.serverPublicKey, keepass.keyPair.secretKey);
|
||||
return keepass.b64e(message);
|
||||
}
|
||||
|
||||
keepass.decrypt = function(input, key, nonce, toStr) {
|
||||
var output = slowAES.decrypt(keepass.b64d(input), slowAES.modeOfOperation.CBC, keepass.b64d(key), keepass.b64d(nonce));
|
||||
//var output = nacl.secretbox.open(keepass.b64d(input), keepass.b64d(nonce), keepass.b64d(key));
|
||||
return toStr ? keepass.to_s(output) : output;
|
||||
}
|
||||
|
||||
keepass.decryptEntry = function (box, key, nonce) {
|
||||
var e = keepass.useSecretBox ? nacl.secretbox.open(box, nonce, key) : box;
|
||||
if (e)
|
||||
{
|
||||
e.uuid = keepass.decrypt(e.uuid, key, nonce, true);
|
||||
e.name = UTF8.decode(keepass.decrypt(e.name, key, nonce, true));
|
||||
e.login = UTF8.decode(keepass.decrypt(e.login, key, nonce, true));
|
||||
e.password = UTF8.decode(keepass.decrypt(e.password, key, nonce, true));
|
||||
|
||||
if(e.StringFields) {
|
||||
for(var i = 0; i < e.StringFields.length; i++) {
|
||||
e.StringFields[i].Key = UTF8.decode(keepass.decrypt(e.StringFields[i].Key, key, nonce, true))
|
||||
e.StringFields[i].Value = UTF8.decode(keepass.decrypt(e.StringFields[i].Value, key, nonce, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
keepass.decrypt = function(input, nonce, toStr) {
|
||||
var m = keepass.b64d(input);
|
||||
var n = keepass.b64d(nonce);
|
||||
return nacl.box.open(m, n, keepass.serverPublicKey, keepass.keyPair.secretKey);
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ chrome.extension.onMessage.addListener(function(req, sender, callback) {
|
|||
}
|
||||
|
||||
var list = {};
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[req.id].StringFields, list)) {
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[req.id].stringFields, list)) {
|
||||
cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
|
||||
}
|
||||
}
|
||||
|
|
@ -1229,7 +1229,7 @@ cip.prepareFieldsForCredentials = function(autoFillInForSingle) {
|
|||
|
||||
if(combination) {
|
||||
var list = {};
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[0].StringFields, list)) {
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[0].stringFields, list)) {
|
||||
cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
|
||||
}
|
||||
}
|
||||
|
|
@ -1449,7 +1449,7 @@ cip.setValueWithChange = function(field, value) {
|
|||
field[0].dispatchEvent(new Event('change', {'bubbles': true}));
|
||||
}
|
||||
|
||||
ip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
||||
cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
||||
// no credentials available
|
||||
if (cip.credentials.length == 0 && !suppressWarnings) {
|
||||
var message = "No logins found.";
|
||||
|
|
@ -1478,7 +1478,7 @@ ip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
}
|
||||
|
||||
var list = {};
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[0].StringFields, list)) {
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[0].stringFields, list)) {
|
||||
cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
|
||||
filledIn = true;
|
||||
}
|
||||
|
|
@ -1508,7 +1508,7 @@ ip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
}
|
||||
|
||||
var list = {};
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[combination.loginId].StringFields, list)) {
|
||||
if(cip.fillInStringFields(combination.fields, cip.credentials[combination.loginId].stringFields, list)) {
|
||||
cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
|
||||
filledIn = true;
|
||||
}
|
||||
|
|
@ -1540,7 +1540,7 @@ ip.fillIn = function(combination, onlyPassword, suppressWarnings) {
|
|||
countPasswords += 1;
|
||||
valPassword = cip.credentials[i].password;
|
||||
valUsername = cip.credentials[i].login;
|
||||
valStringFields = cip.credentials[i].StringFields;
|
||||
valStringFields = cip.credentials[i].stringFields;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,6 @@
|
|||
</div>
|
||||
<img src="/options/http-auth-dialog.png" alt="http-auth-dialog" />
|
||||
</p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<!-- Connected Databases -->
|
||||
|
|
|
|||
Loading…
Reference in a new issue