mirror of
https://github.com/darkwire/darkwire.io.git
synced 2025-07-18 18:54:52 +00:00
Revert "Use asymmetric signing keys instead of HMAC"
This reverts commit 323c7a903db4fa00c7a93d199862a3f0118b608f.
This commit is contained in:
parent
9c9c08b29c
commit
0fc55576fe
22
readme.md
22
readme.md
@ -18,23 +18,25 @@ Build source
|
||||
|
||||
### How it works
|
||||
|
||||
Darkwire uses a combination of asymmetric encryption (RSA-OAEP), asymmetric signing (RSASSA-PKCS1-v1_5) and symmetric session encryption (AES-CBC) for security.
|
||||
Darkwire uses a combination of asymmetric encryption (RSA-OAEP), symmetric session keys (AES-CBC) and signing keys (HMAC) for security.
|
||||
|
||||
Here's an overview of a chat between Alice and Bob (also applies to group chats):
|
||||
|
||||
1. Bob creates a room and immediately creates both a primary public/private key pair (RSA-OAEP) and a signing public/private key pair (RSASSA-PKCS1-v1_5).
|
||||
2. Alice joins the room and also creates primary and signing public/private key pairs. She is sent Bob's two public keys and she sends Bob her two public keys.
|
||||
3. When Bob goes to send a message, two things are created: a session key (AES-CBC) and an initialization vector (these are generated every time a new message is sent).
|
||||
4. Bob's message is encrypted with the session key and initialization vector, and a signature is created using his private signing key.
|
||||
5. The session key is encrypted with each recipient's primary public key (in this case only Alice, but in a group chat multiple).
|
||||
6. The encrypted message, initialization vector, signature and encrypted session key are sent to all recipients (in this case just Alice) as a package.
|
||||
7. Alice receives the package and decrypts the session key using her primary private key. She decrypts the message with the decrypted session key and vector, and verifies the signature with Bob's public signing key.
|
||||
1. Bob creates a room and immediately creates a public/private key pair (RSA-OAEP).
|
||||
2. Alice joins the room and also creates a public/private key pair. She is sent Bob's public key and she sends Bob her public key.
|
||||
3. When Bob goes to send a message, three things are created: a session key (AES-CBC), a signing key (HMAC SHA-256) and an initialization vector (used in the encryption process).
|
||||
4. Bob's message is encrypted with the session key and initialization vector, and a signature is created using the signing key.
|
||||
5. The session key and signing key are encrypted with each recipient's public key (in this case only Alice, but in a group chat multiple).
|
||||
6. The encrypted message, initialization vector, signature, encrypted session key and encrypted signing key are sent to all recipients (in this case just Alice) as a package.
|
||||
7. Alice receives the package and decrypts the session key and signing key using her private key. She decrypts the message with the decrypted session key and vector, and verifies the signature with the decrypted signing key.
|
||||
|
||||
Group chats work the same way because in step 5 we encrypt the session key with everyone's primary public key. When a message is sent out, it includes encrypted keys for everyone in the room, and the recipients then pick out the ones for them based on their user ID.
|
||||
Group chats work the same way because in step 5 we encrypt keys with everyone's public key. When a message is sent out, it includes encrypted keys for everyone in the room, and the recipients then pick out the ones for them based on their user ID.
|
||||
|
||||
### [Man-in-the-middle attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)
|
||||
|
||||
Darkwire does not provide any guarantee that the person you're communicating with is who you think they are. Authentication functionality may be incorporated in future versions.
|
||||
Darkwire does not provide any guarantee that the person you're communicating with is who you think they are (authentication).
|
||||
|
||||
A good idea is to ask the recipient a question, the answer to which only they should know. Or, ask them to enter a pass phrase you've agreed upon in advance. This functionality may be incorporated In future versions.
|
||||
|
||||
### Sockets & Server
|
||||
|
||||
|
@ -90,31 +90,22 @@ $(function() {
|
||||
$inputMessage.focus();
|
||||
|
||||
Promise.all([
|
||||
createPrimaryKeys(),
|
||||
createSigningKeys()
|
||||
createPrimaryKeys()
|
||||
])
|
||||
.then(function(data) {
|
||||
keys = {
|
||||
primary: {
|
||||
public: data[0].publicKey,
|
||||
private: data[0].privateKey
|
||||
},
|
||||
signing: {
|
||||
public: data[1].publicKey,
|
||||
private: data[1].privateKey
|
||||
}
|
||||
};
|
||||
return Promise.all([
|
||||
exportKey(data[0].publicKey, "spki"),
|
||||
exportKey(data[1].publicKey, "jwk")
|
||||
exportKey(data[0].publicKey, "spki")
|
||||
]);
|
||||
})
|
||||
.then(function(exportedKeys) {
|
||||
// Tell the server your username and send public keys
|
||||
socket.emit('add user', {
|
||||
username: username,
|
||||
primaryPublicKey: exportedKeys[0],
|
||||
signingPublicKey: exportedKeys[1],
|
||||
publicKey: exportedKeys[0]
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -308,15 +299,13 @@ $(function() {
|
||||
let promise = new Promise(function(resolve, reject) {
|
||||
let currentUser = user;
|
||||
Promise.all([
|
||||
importPrimaryKey(currentUser.primaryPublicKey, "spki"),
|
||||
importSigningKey(currentUser.signingPublicKey)
|
||||
importPrimaryKey(currentUser.publicKey, "spki")
|
||||
])
|
||||
.then(function(keys) {
|
||||
users.push({
|
||||
id: currentUser.id,
|
||||
username: currentUser.username,
|
||||
primaryPublicKey: keys[0],
|
||||
signingPublicKey: keys[1]
|
||||
publicKey: keys[0]
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
@ -367,12 +356,17 @@ $(function() {
|
||||
let secretKeys;
|
||||
let messageData;
|
||||
let signature;
|
||||
let signingKey;
|
||||
let encryptedMessageData;
|
||||
|
||||
// Generate new secret key and vector for each message
|
||||
createSecretKey()
|
||||
.then(function(key) {
|
||||
secretKey = key;
|
||||
return createSigningKey();
|
||||
})
|
||||
.then(function(key) {
|
||||
signingKey = key;
|
||||
// Generate secretKey and encrypt with each user's public key
|
||||
let promises = [];
|
||||
_.each(users, function(user) {
|
||||
@ -386,14 +380,25 @@ $(function() {
|
||||
// Export secret key
|
||||
exportKey(secretKey, "raw")
|
||||
.then(function(data) {
|
||||
return encryptSecretKey(data, thisUser.primaryPublicKey);
|
||||
return encryptSecretKey(data, thisUser.publicKey);
|
||||
})
|
||||
.then(function(encryptedSecretKey) {
|
||||
let encData = new Uint8Array(encryptedSecretKey);
|
||||
secretKeyStr = convertArrayBufferViewToString(encData);
|
||||
// Export HMAC signing key
|
||||
return exportKey(signingKey, "raw");
|
||||
})
|
||||
.then(function(data) {
|
||||
// Encrypt signing key with user's public key
|
||||
return encryptSigningKey(data, thisUser.publicKey);
|
||||
})
|
||||
.then(function(encryptedSigningKey) {
|
||||
let encData = new Uint8Array(encryptedSigningKey);
|
||||
var str = convertArrayBufferViewToString(encData);
|
||||
resolve({
|
||||
id: thisUser.id,
|
||||
secretKey: secretKeyStr
|
||||
secretKey: secretKeyStr,
|
||||
encryptedSigningKey: str
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -405,7 +410,7 @@ $(function() {
|
||||
.then(function(data) {
|
||||
secretKeys = data;
|
||||
messageData = convertStringToArrayBufferView(message);
|
||||
return signKey(messageData, keys.signing.private);
|
||||
return signKey(messageData, signingKey);
|
||||
})
|
||||
.then(function(data) {
|
||||
signature = data;
|
||||
@ -440,7 +445,7 @@ $(function() {
|
||||
let message = data.message;
|
||||
let messageData = convertStringToArrayBufferView(message);
|
||||
let username = data.username;
|
||||
let senderId = data.id;
|
||||
let senderId = data.id
|
||||
let vector = data.vector;
|
||||
let vectorData = convertStringToArrayBufferView(vector);
|
||||
let secretKeys = data.secretKeys;
|
||||
@ -453,10 +458,9 @@ $(function() {
|
||||
let signature = data.signature;
|
||||
let signatureData = convertStringToArrayBufferView(signature);
|
||||
let secretKeyArrayBuffer = convertStringToArrayBufferView(mySecretKey.secretKey);
|
||||
let signingKeyArrayBuffer = convertStringToArrayBufferView(mySecretKey.encryptedSigningKey);
|
||||
|
||||
let sender = _.findWhere(users, {id: senderId});
|
||||
|
||||
decryptSecretKey(secretKeyArrayBuffer, keys.primary.private)
|
||||
decryptSecretKey(secretKeyArrayBuffer, keys.private)
|
||||
.then(function(data) {
|
||||
return importSecretKey(new Uint8Array(data), "raw");
|
||||
})
|
||||
@ -466,8 +470,15 @@ $(function() {
|
||||
})
|
||||
.then(function(data) {
|
||||
decryptedMessageData = data;
|
||||
decryptedMessage = convertArrayBufferViewToString(new Uint8Array(data));
|
||||
return verifyKey(signatureData, decryptedMessageData, sender.signingPublicKey);
|
||||
decryptedMessage = convertArrayBufferViewToString(new Uint8Array(data))
|
||||
return decryptSigningKey(signingKeyArrayBuffer, keys.private)
|
||||
})
|
||||
.then(function(data) {
|
||||
return importSigningKey(new Uint8Array(data), "raw");
|
||||
})
|
||||
.then(function(data) {
|
||||
let signingKey = data;
|
||||
return verifyKey(signatureData, decryptedMessageData, signingKey);
|
||||
})
|
||||
.then(function(bool) {
|
||||
if (bool) {
|
||||
@ -577,13 +588,12 @@ $(function() {
|
||||
return str;
|
||||
}
|
||||
|
||||
function createSigningKeys() {
|
||||
function createSigningKey() {
|
||||
return window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: "RSASSA-PKCS1-v1_5",
|
||||
modulusLength: 2048, //can be 1024, 2048, or 4096
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
name: "HMAC",
|
||||
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
//length: 256, //optional, if you want your key length to differ from the hash function's block length
|
||||
},
|
||||
true, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
["sign", "verify"] //can be any combination of "sign" and "verify"
|
||||
@ -737,13 +747,15 @@ $(function() {
|
||||
|
||||
function importSigningKey(jwkData) {
|
||||
return window.crypto.subtle.importKey(
|
||||
"jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
|
||||
"raw", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
|
||||
//this is an example jwk key, other key types are Uint8Array objects
|
||||
jwkData,
|
||||
{ //these are the algorithm options
|
||||
name: "RSASSA-PKCS1-v1_5",
|
||||
name: "HMAC",
|
||||
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
//length: 256, //optional, if you want your key length to differ from the hash function's block length
|
||||
},
|
||||
false, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
true, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
["verify"] //"verify" for public key import, "sign" for private key imports
|
||||
);
|
||||
}
|
||||
@ -752,10 +764,8 @@ $(function() {
|
||||
// Will use my private key
|
||||
return window.crypto.subtle.sign(
|
||||
{
|
||||
name: "RSASSA-PKCS1-v1_5",
|
||||
modulusLength: 2048, //can be 1024, 2048, or 4096
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
name: "HMAC",
|
||||
hash: {name: "SHA-256"}
|
||||
},
|
||||
keyToSignWith, //from generateKey or importKey above
|
||||
data //ArrayBuffer of data you want to sign
|
||||
@ -766,10 +776,8 @@ $(function() {
|
||||
// Will verify with sender's public key
|
||||
return window.crypto.subtle.verify(
|
||||
{
|
||||
name: "RSASSA-PKCS1-v1_5",
|
||||
modulusLength: 2048, //can be 1024, 2048, or 4096
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
name: "HMAC",
|
||||
hash: {name: "SHA-256"}
|
||||
},
|
||||
keyToVerifyWith, //from generateKey or importKey above
|
||||
signature, //ArrayBuffer of the signature
|
||||
|
Loading…
x
Reference in New Issue
Block a user