From 829e475b62720dfb42ae7350c768695e0d1c339e Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Wed, 27 Dec 2017 18:36:42 +0000 Subject: [PATCH 01/15] HandShake protocol refactory --- src/cryptoManager/CryptoManager.js | 453 ++----------------------- src/cryptoManager/HandShakeProtocol.js | 450 ++++++++++++++++++++++++ src/identity/IdentityManager.js | 7 +- src/identity/IdentityModule.js | 2 +- src/utils/utils.js | 26 +- 5 files changed, 510 insertions(+), 428 deletions(-) create mode 100644 src/cryptoManager/HandShakeProtocol.js diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index 03c0daad..76d3c992 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -1,9 +1,11 @@ // Log System import * as logger from 'loglevel'; let log = logger.getLogger('CryptoManager'); +import HandShakeProtocol from './HandShakeProtocol'; import {divideURL, isDataObjectURL, isLegacy, chatkeysToStringCloner, chatkeysToArrayCloner, parseMessageURL, - parse, stringify, encode, decode, decodeToUint8Array, parseToUint8Array} from '../utils/utils.js'; + parse, stringify, encode, decode, decodeToUint8Array, filterMessageToHash} from '../utils/utils.js'; + import Crypto from './Crypto'; /** @@ -44,6 +46,7 @@ class CryptoManager { _this._domain = divideURL(_this._runtimeURL).domain; _this.crypto = new Crypto(_this._runtimeFactory); + _this.handShakeProtocol = new HandShakeProtocol(_this.crypto); // hashTable to store all the crypto information between two hyperties _this.chatKeys = {}; @@ -292,7 +295,7 @@ class CryptoManager { let iv = _this.crypto.generateIV(); _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, stringify(message.body.value), iv).then(encryptedValue => { - let filteredMessage = _this._filterMessageToHash(message, stringify(message.body.value) + + let filteredMessage = filterMessageToHash(message, stringify(message.body.value) + stringify(iv), chatKeys.hypertyFrom.messageInfo); _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { @@ -361,7 +364,7 @@ class CryptoManager { _this.crypto.encryptAES(dataObjectKey.sessionKey, stringifiedMessageBody, iv).then(encryptedValue => { delete message.body.identity.assertion; //TODO: Check why assertion is comming on the message! delete message.body.identity.expires; //TODO: Check why expires is comming on the message! - let filteredMessage = _this._filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); + let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { // log.log('hash ', hash); @@ -472,12 +475,15 @@ class CryptoManager { // log.log('decrypted value ', decryptedData); message.body.value = decryptedData; - let filteredMessage = _this._filterMessageToHash(message, decryptedData + iv); + let filteredMessage = filterMessageToHash(message, decryptedData + iv); _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { - //log.log('result of hash verification! ', result); + log.log('Result of hash verification in decryptMessage: ', result); message.body.assertedIdentity = true; resolve(message); + }).chatch(err => { + console.log('decryptMessage HMAC failed:', err); + throw err; }); }); @@ -526,7 +532,7 @@ class CryptoManager { // log.log('decrypted Value,', parsedValue); message.body.value = parsedValue; - let filteredMessage = _this._filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); + let filteredMessage = filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); _this.crypto.verifyHMAC(dataObjectKey.sessionKey, filteredMessage, hash).then(result => { log.log('Received message HMAC result', result); @@ -790,7 +796,7 @@ class CryptoManager { } }; - let filteredMessage = _this._filterMessageToHash(reporterSessionKeyMsg, valueToEncrypt + iv, chatKeys.hypertyFrom.messageInfo); + let filteredMessage = filterMessageToHash(reporterSessionKeyMsg, valueToEncrypt + iv, chatKeys.hypertyFrom.messageInfo); return _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage); }).then(hashedMessage => { @@ -817,6 +823,7 @@ class CryptoManager { } } + _doHandShakePhase(message, chatKeys) { // log('_doHandShakePhase:dataObject', message); // log('_doHandShakePhase:chatKeys', chatKeys); @@ -826,420 +833,43 @@ class CryptoManager { return new Promise(function(resolve, reject) { let handshakeType = message.body.handshakePhase; - let iv; - let hash; - let value = {}; - let filteredMessage; - let privateKeyHolder; - console.info('handshake phase: ', handshakeType); switch (handshakeType) { - case 'startHandShake': { - chatKeys.keys.fromRandom = _this.crypto.generateRandom(); - let startHandShakeMsg = { - type: 'handshake', - to: message.to, - from: message.from, - body: { - handshakePhase: 'senderHello', - value: encode(chatKeys.keys.fromRandom) - } - }; - chatKeys.handshakeHistory.senderHello = _this._filterMessageToHash(startHandShakeMsg, undefined, chatKeys.hypertyFrom.messageInfo); - - // check if was the encrypt function or the mutual authentication that request the - // start of the handShakePhase. - - if (chatKeys.initialMessage) { - resolve({message: startHandShakeMsg, chatKeys: chatKeys}); - } else { - _this.chatKeys[message.from + '<->' + message.to] = chatKeys; - _this._messageBus.postMessage(startHandShakeMsg); - } - + case 'startHandShake': + _this.handShakeProtocol.startHandShake(message, chatKeys).then(result => { resolve(result); }); break; - } - case 'senderHello': { - - log.log('senderHello'); - chatKeys.handshakeHistory.senderHello = _this._filterMessageToHash(message); - chatKeys.keys.fromRandom = decodeToUint8Array(message.body.value); - chatKeys.keys.toRandom = _this.crypto.generateRandom(); - - let senderHelloMsg = { - type: 'handshake', - to: message.from, - from: message.to, - body: { - handshakePhase: 'receiverHello', - value: encode(chatKeys.keys.toRandom) - } - }; - chatKeys.handshakeHistory.receiverHello = _this._filterMessageToHash(senderHelloMsg, undefined, chatKeys.hypertyFrom.messageInfo); - resolve({message: senderHelloMsg, chatKeys: chatKeys}); - + case 'senderHello': + _this.handShakeProtocol.senderHello(message, chatKeys).then(result => { resolve(result); }); break; - } - case 'receiverHello': { - - log.log('receiverHello'); - _this.getMyPrivateKey().then(privateKey =>{ - privateKeyHolder = privateKey; - - chatKeys.handshakeHistory.receiverHello = _this._filterMessageToHash(message); - - return _this._idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain); - }).then((value) => { - - //TODO remove later this verification as soon as all the IdP proxy are updated in the example - let encodedpublicKey = (typeof value.contents === 'string') ? value.contents : value.contents.nonce; - - let receiverPublicKey = parseToUint8Array(encodedpublicKey); - let premasterSecret = _this.crypto.generatePMS(); - let toRandom = message.body.value; - chatKeys.hypertyTo.assertion = message.body.identity.assertion; - chatKeys.hypertyTo.publicKey = receiverPublicKey; - chatKeys.hypertyTo.userID = value.contents.email; - chatKeys.keys.toRandom = decodeToUint8Array(toRandom); - chatKeys.keys.premasterKey = premasterSecret; - - let concatKey = _this.crypto.concatPMSwithRandoms(premasterSecret, chatKeys.keys.toRandom, chatKeys.keys.fromRandom); - - return _this.crypto.generateMasterSecret(concatKey, 'messageHistoric' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); - - //generate the master key - }).then((masterKey) => { - chatKeys.keys.masterKey = masterKey; - - return _this.crypto.generateKeys(masterKey, 'key expansion' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); - - //generate the symmetric and hash keys - }).then((keys) => { - - chatKeys.keys.hypertyToSessionKey = new Uint8Array(keys[0]); - chatKeys.keys.hypertyFromSessionKey = new Uint8Array(keys[1]); - chatKeys.keys.hypertyToHashKey = new Uint8Array(keys[2]); - chatKeys.keys.hypertyFromHashKey = new Uint8Array(keys[3]); - iv = _this.crypto.generateIV(); - value.iv = encode(iv); - - let messageStructure = { - type: 'handshake', - to: message.from, - from: message.to, - body: { - handshakePhase: 'senderCertificate' - } - }; - - // hash the value and the iv - filteredMessage = _this._filterMessageToHash(messageStructure, 'ok' + iv, chatKeys.hypertyFrom.messageInfo); - return _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage); - }).then((hash) => { - value.hash = encode(hash); - - //encrypt the data - return _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, 'ok', iv); - }).then((encryptedData) => { - value.symetricEncryption = encode(encryptedData); - - return _this.crypto.encryptRSA(chatKeys.hypertyTo.publicKey, chatKeys.keys.premasterKey); - - }).then((encryptedValue) => { - value.assymetricEncryption = encode(encryptedValue); - - let messageStructure = { - type: 'handshake', - to: message.from, - from: message.to, - body: { - handshakePhase: 'senderCertificate' - } - }; - - let messageToHash = _this._filterMessageToHash(messageStructure, chatKeys.keys.premasterKey, chatKeys.hypertyFrom.messageInfo); - return _this.crypto.signRSA(privateKeyHolder, encode(chatKeys.handshakeHistory) + encode(messageToHash)); - }).then(signature => { - - value.signature = encode(signature); - - let receiverHelloMsg = { - type: 'handshake', - to: message.from, - from: message.to, - body: { - handshakePhase: 'senderCertificate', - value: encode(value) - } - }; - chatKeys.handshakeHistory.senderCertificate = _this._filterMessageToHash(receiverHelloMsg, 'ok' + iv, chatKeys.hypertyFrom.messageInfo); - - resolve({message: receiverHelloMsg, chatKeys: chatKeys}); - - }, error => reject(error)); + case 'receiverHello': + _this.handShakeProtocol.receiverHello(message, chatKeys).then(result => { resolve(result); }) + .catch(err => { reject(err); }); break; - } - case 'senderCertificate': { - - log.log('senderCertificate'); - - let receivedValue = decode(message.body.value); - - _this.getMyPrivateKey().then(privateKey =>{ - privateKeyHolder = privateKey; - - return _this._idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain); - }).then((value) => { - let encryptedPMS = decodeToUint8Array(receivedValue.assymetricEncryption); - - //TODO remove later this verification as soon as all the IdP proxy are updated in the example - let encodedpublicKey = (typeof value.contents === 'string') ? value.contents : value.contents.nonce; - - let senderPublicKey = parseToUint8Array(encodedpublicKey); - chatKeys.hypertyTo.assertion = message.body.identity.assertion; - chatKeys.hypertyTo.publicKey = senderPublicKey; - chatKeys.hypertyTo.userID = value.contents.email; - - return _this.crypto.decryptRSA(privateKeyHolder, encryptedPMS); - - }, (error) => { - // log.log(error); - reject('Error during authentication of identity: ', error.message); - - //obtain the PremasterKey using the private key - }).then(pms => { - - chatKeys.keys.premasterKey = new Uint8Array(pms); - - let signature = decodeToUint8Array(receivedValue.signature); - - let receivedmsgToHash = _this._filterMessageToHash(message, chatKeys.keys.premasterKey); - - return _this.crypto.verifyRSA(chatKeys.hypertyTo.publicKey, encode(chatKeys.handshakeHistory) + encode(receivedmsgToHash), signature); - - // validates the signature received - }).then(signValidationResult => { - - //log.log('SenderCertificate - signature validation result ', signValidationResult); - let concatKey = _this.crypto.concatPMSwithRandoms(chatKeys.keys.premasterKey, chatKeys.keys.toRandom, chatKeys.keys.fromRandom); - - return _this.crypto.generateMasterSecret(concatKey, 'messageHistoric' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); - - // generates the master keys from the Premaster key and the randoms - }).then(masterKey => { - chatKeys.keys.masterKey = masterKey; - - return _this.crypto.generateKeys(masterKey, 'key expansion' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); - - // generates the symmetric keys to be used in the symmetric encryption - }).then(keys => { - chatKeys.keys.hypertyFromSessionKey = new Uint8Array(keys[0]); - chatKeys.keys.hypertyToSessionKey = new Uint8Array(keys[1]); - chatKeys.keys.hypertyFromHashKey = new Uint8Array(keys[2]); - chatKeys.keys.hypertyToHashKey = new Uint8Array(keys[3]); - iv = decodeToUint8Array(receivedValue.iv); - let data = decodeToUint8Array(receivedValue.symetricEncryption); - - return _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv); - - }).then(decryptedData => { - // log.log('decryptedData', decryptedData); - - chatKeys.handshakeHistory.senderCertificate = _this._filterMessageToHash(message, decryptedData + iv); - - let hashReceived = decodeToUint8Array(receivedValue.hash); - - filteredMessage = _this._filterMessageToHash(message, decryptedData + iv); - - return _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hashReceived); - - }).then(verifiedHash => { - - // log.log('result of hash verification ', verifiedHash); - let receiverFinishedMessage = { - type: 'handshake', - to: message.from, - from: message.to, - body: { - handshakePhase: 'receiverFinishedMessage' - } - }; - iv = _this.crypto.generateIV(); - value.iv = encode(iv); - - filteredMessage = _this._filterMessageToHash(receiverFinishedMessage, 'ok!' + iv, chatKeys.hypertyFrom.messageInfo); - - //log.log('TIAGO: doHandShakePhase verifiedHash'); - return _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage); - }).then(hash => { - - value.hash = encode(hash); - return _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, 'ok!', iv); - - }).then(encryptedValue => { - value.value = encode(encryptedValue); - let receiverFinishedMessage = { - type: 'handshake', - to: message.from, - from: message.to, - body: { - handshakePhase: 'receiverFinishedMessage', - value: encode(value) - } - }; - - chatKeys.handshakeHistory.receiverFinishedMessage = _this._filterMessageToHash(receiverFinishedMessage, 'ok!' + iv, chatKeys.hypertyFrom.messageInfo); - chatKeys.authenticated = true; - resolve({message: receiverFinishedMessage, chatKeys: chatKeys}); - }).catch(err => { - reject('On _doHandShakePhase from senderCertificate error: ' + err); - }); + case 'senderCertificate': + _this.handShakeProtocol.senderCertificate(message, chatKeys).then(result => { resolve(result); }) + .catch(err => { reject(err); }); break; - } - case 'receiverFinishedMessage': { - - chatKeys.authenticated = true; - - value = decode(message.body.value); - - iv = decodeToUint8Array(value.iv); - let data = decodeToUint8Array(value.value); - hash = decodeToUint8Array(value.hash); - - _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { - // log.log('decryptedData', decryptedData); - chatKeys.handshakeHistory.receiverFinishedMessage = _this._filterMessageToHash(message, decryptedData + iv); - - let filteredMessage = _this._filterMessageToHash(message, decryptedData + iv); - _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { - - // check if there was an initial message that was blocked and send it - if (chatKeys.initialMessage) { - - let initialMessage = { - type: 'create', - to: message.from, - from: message.to, - body: { - value: chatKeys.initialMessage.body.value - } - }; - - resolve({message: initialMessage, chatKeys: chatKeys}); - - //sends the sessionKey to the subscriber hyperty - } else { - _this._sendReporterSessionKey(message, chatKeys).then(value => { - - resolve(value); - }).catch(err => { - reject('On _doHandShakePhase from receiverFinishedMessage error: ' + err); - }); - } - }); - }); + case 'receiverFinishedMessage': { + _this.handShakeProtocol.receiverFinishedMessage(message, chatKeys).then(result => { resolve(result); }) + .catch(err => { reject(err); }); break; } case 'reporterSessionKey': { - - log.log('reporterSessionKey'); - - let valueIVandHash = decode(message.body.value); - hash = decodeToUint8Array(valueIVandHash.hash); - iv = decodeToUint8Array(valueIVandHash.iv); - let encryptedValue = decodeToUint8Array(valueIVandHash.value); - let parsedValue; - let sessionKey; - let dataObjectURL; - let receiverAcknowledgeMsg; - - //log.log('[IdentityModule reporterSessionKey] - decryptAES: ', chatKeys.keys.hypertyToSessionKey, encryptedValue, iv); - - _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, encryptedValue, iv).then(decryptedValue => { - - parsedValue = decode(decryptedValue); - sessionKey = decodeToUint8Array(parsedValue.value); - dataObjectURL = parsedValue.dataObjectURL; - - let messageToHash = _this._filterMessageToHash(message, decryptedValue + iv); - - return _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, messageToHash, hash); - - }).then(hashResult => { - - - // log.log('hash successfully validated ', hashResult); - - _this.dataObjectSessionKeys[dataObjectURL] = {sessionKey: sessionKey, isToEncrypt: true}; - let dataObjectSessionKeysClone = chatkeysToStringCloner(_this.dataObjectSessionKeys); - _this.storageManager.set('dataObjectSessionKeys', 0, dataObjectSessionKeysClone).catch(err => { - reject('On _sendReporterSessionKey from method reporterSessionKey error: ' + err); - }); - - iv = _this.crypto.generateIV(); - value.iv = encode(iv); - - return _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, 'ok!!', iv); - }).then(encryptedValue => { - - receiverAcknowledgeMsg = { - type: 'handshake', - to: message.from, - from: message.to, - body: { - handshakePhase: 'receiverAcknowledge' - } - }; - - value.value = encode(encryptedValue); - let messageToHash = _this._filterMessageToHash(receiverAcknowledgeMsg, 'ok!!' + iv, chatKeys.hypertyFrom.messageInfo); - - return _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, messageToHash); - }).then(hashedMessage => { - let finalValue = encode({value: value.value, hash: encode(hashedMessage), iv: value.iv}); - - receiverAcknowledgeMsg.body.value = finalValue; - resolve({message: receiverAcknowledgeMsg, chatKeys: chatKeys}); - }).catch(err => { - reject('On _doHandShakePhase from reporterSessionKey error: ' + err); - }); - + _this.handShakeProtocol.reporterSessionKey(message, chatKeys).then(result => { resolve(result); }) + .catch(err => { reject(err); }); break; } case 'receiverAcknowledge': { - - log.log('receiverAcknowledge'); - - let receivedvalueIVandHash = decode(message.body.value); - let receivedHash = decodeToUint8Array(receivedvalueIVandHash.hash); - iv = decodeToUint8Array(receivedvalueIVandHash.iv); - let receivedEncryptedValue = decodeToUint8Array(receivedvalueIVandHash.value); - - _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, receivedEncryptedValue, iv).then(decryptedValue => { - - let filteredMessage = _this._filterMessageToHash(message, decryptedValue + iv); - return _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, receivedHash); - }).then(hashResult => { - // log.log('hashResult ', hashResult); - - let callback = chatKeys.callback; - - if (callback) { - callback('handShakeEnd'); - } - resolve('handShakeEnd'); - }).catch(err => { - reject('On _doHandShakePhase from receiverAcknowledge error: ' + err); - }); - + _this.handShakeProtocol.receiverAcknowledge(message, chatKeys).then(result => { resolve(result); }) + .catch(err => { reject(err); }); break; } @@ -1249,26 +879,6 @@ class CryptoManager { }); } - /** - * filter the messages to hash, by removing some fields not generated by the runtime core - * @param {Message} message message - * @param {String} decryptedValue (Optional) value from body.value in case it originally comes encrypted - * @param {JSON} identity(Optional) add the hyperty identity associated in case is not added to the initial message - * @return {Message} new message filtered - */ - _filterMessageToHash(message, decryptedValue, identity) { - - return { - type: message.type, - from: message.from, - to: message.to, - body: { - identity: identity || message.body.identity, - value: decryptedValue || message.body.value, - handshakePhase: message.body.handshakePhase - } - }; - } /** * generates the initial structure for the keys between two users @@ -1416,4 +1026,5 @@ const nodeJSKeyPairPopulate = { public: [48, 130, 1, 34, 48, 13, 6, 9, 42, 134, private: [48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 228, 43, 101, 12, 121, 7, 157, 71, 81, 58, 219, 32, 10, 108, 193, 179, 212, 116, 255, 59, 217, 32, 161, 201, 53, 171, 226, 199, 137, 202, 171, 60, 82, 53, 125, 62, 177, 126, 165, 24, 141, 30, 15, 226, 59, 107, 34, 7, 13, 149, 112, 125, 10, 230, 191, 156, 164, 177, 10, 185, 13, 66, 3, 217, 166, 244, 90, 119, 111, 27, 145, 104, 71, 189, 166, 226, 255, 133, 83, 151, 231, 101, 151, 89, 22, 19, 65, 154, 10, 53, 208, 218, 252, 219, 37, 50, 212, 86, 145, 107, 132, 90, 233, 202, 227, 108, 114, 141, 29, 73, 187, 31, 13, 234, 0, 232, 24, 191, 35, 149, 179, 138, 214, 159, 245, 162, 148, 221, 118, 17, 105, 89, 151, 146, 209, 55, 236, 61, 143, 233, 228, 10, 115, 8, 81, 197, 45, 123, 187, 223, 176, 254, 165, 69, 143, 29, 100, 114, 17, 130, 226, 223, 33, 11, 240, 81, 61, 172, 191, 157, 246, 202, 87, 131, 221, 88, 48, 127, 159, 119, 160, 152, 117, 61, 253, 174, 65, 214, 203, 218, 63, 50, 78, 160, 181, 221, 211, 128, 70, 178, 191, 170, 0, 13, 122, 173, 12, 203, 252, 4, 184, 225, 252, 7, 62, 96, 116, 15, 216, 158, 55, 85, 48, 16, 9, 206, 119, 74, 112, 243, 136, 84, 184, 223, 254, 101, 91, 61, 10, 91, 85, 192, 147, 144, 57, 29, 66, 238, 199, 244, 193, 194, 150, 232, 200, 107, 2, 3, 1, 0, 1, 2, 130, 1, 0, 103, 244, 137, 118, 116, 82, 14, 203, 102, 107, 253, 88, 12, 199, 222, 60, 243, 136, 86, 157, 74, 224, 190, 53, 113, 57, 157, 250, 49, 130, 96, 31, 252, 136, 152, 70, 143, 17, 215, 96, 103, 51, 18, 35, 141, 212, 210, 205, 9, 216, 83, 70, 245, 71, 138, 119, 112, 229, 164, 176, 9, 37, 81, 161, 193, 154, 68, 249, 115, 106, 201, 6, 12, 225, 144, 126, 141, 210, 141, 242, 128, 159, 221, 163, 222, 21, 233, 230, 167, 206, 59, 24, 250, 233, 81, 122, 102, 26, 6, 233, 72, 133, 47, 77, 155, 238, 86, 6, 139, 24, 131, 163, 179, 112, 48, 247, 142, 6, 207, 204, 173, 223, 140, 199, 150, 95, 123, 152, 202, 155, 131, 238, 62, 96, 133, 4, 217, 51, 121, 30, 38, 178, 189, 216, 44, 35, 241, 93, 7, 62, 90, 111, 216, 66, 209, 243, 128, 234, 141, 84, 135, 181, 13, 38, 220, 114, 245, 240, 178, 95, 220, 206, 11, 186, 234, 213, 66, 121, 83, 68, 89, 75, 46, 183, 145, 183, 147, 160, 215, 118, 198, 125, 181, 146, 30, 251, 58, 87, 47, 209, 237, 97, 24, 47, 179, 6, 110, 242, 99, 150, 226, 148, 198, 174, 146, 101, 213, 87, 178, 10, 223, 105, 18, 56, 53, 22, 212, 158, 170, 176, 51, 86, 145, 125, 124, 44, 9, 85, 19, 144, 246, 170, 78, 124, 30, 32, 12, 166, 174, 139, 77, 63, 173, 82, 10, 153, 2, 129, 129, 0, 248, 18, 143, 246, 137, 136, 145, 219, 178, 39, 27, 94, 64, 90, 47, 163, 114, 60, 63, 187, 131, 143, 244, 16, 42, 128, 231, 117, 92, 98, 219, 155, 62, 107, 252, 17, 245, 45, 160, 225, 103, 142, 72, 36, 193, 150, 235, 214, 175, 62, 212, 56, 45, 9, 0, 60, 114, 107, 134, 228, 204, 131, 131, 214, 94, 201, 148, 159, 99, 139, 181, 13, 119, 38, 30, 107, 166, 165, 203, 43, 34, 20, 207, 171, 32, 58, 167, 62, 196, 153, 103, 204, 213, 247, 48, 111, 227, 59, 95, 97, 194, 187, 53, 10, 247, 108, 58, 86, 28, 29, 113, 8, 110, 171, 220, 245, 11, 82, 233, 223, 91, 68, 166, 117, 174, 187, 62, 77, 2, 129, 129, 0, 235, 118, 2, 105, 239, 212, 30, 104, 157, 41, 109, 11, 248, 152, 22, 236, 97, 40, 153, 131, 228, 5, 86, 187, 113, 126, 144, 76, 141, 79, 110, 250, 146, 152, 49, 58, 156, 201, 176, 92, 189, 209, 30, 112, 108, 175, 204, 204, 247, 164, 46, 129, 239, 98, 127, 49, 145, 218, 63, 193, 124, 174, 18, 98, 201, 99, 154, 162, 138, 78, 159, 253, 3, 248, 3, 209, 36, 239, 193, 155, 193, 5, 19, 236, 37, 78, 118, 135, 250, 199, 7, 141, 248, 120, 36, 136, 93, 98, 174, 60, 18, 215, 93, 174, 107, 141, 116, 145, 167, 221, 210, 169, 247, 67, 254, 222, 161, 134, 63, 221, 90, 87, 42, 99, 227, 81, 173, 151, 2, 129, 129, 0, 133, 23, 168, 103, 83, 232, 146, 160, 181, 23, 40, 38, 204, 13, 214, 203, 49, 41, 195, 227, 189, 181, 8, 243, 119, 106, 75, 67, 250, 250, 10, 234, 98, 118, 26, 250, 35, 121, 132, 124, 10, 76, 26, 198, 165, 154, 108, 19, 117, 88, 23, 17, 192, 143, 184, 177, 181, 141, 157, 4, 185, 248, 193, 77, 204, 243, 7, 170, 240, 4, 111, 113, 183, 0, 27, 136, 20, 19, 149, 74, 33, 241, 218, 108, 236, 80, 171, 148, 16, 116, 97, 109, 83, 74, 88, 145, 94, 239, 102, 192, 19, 114, 207, 5, 128, 51, 111, 164, 237, 86, 154, 99, 52, 197, 62, 57, 182, 6, 152, 245, 61, 137, 58, 105, 159, 2, 84, 109, 2, 129, 129, 0, 226, 67, 111, 132, 95, 91, 101, 177, 63, 189, 44, 53, 193, 184, 92, 230, 223, 98, 133, 74, 209, 86, 52, 7, 65, 195, 206, 100, 81, 178, 144, 65, 167, 151, 42, 79, 89, 149, 18, 173, 188, 21, 244, 251, 49, 230, 41, 150, 153, 46, 35, 38, 231, 99, 174, 56, 115, 32, 215, 253, 85, 147, 108, 197, 147, 34, 236, 216, 222, 177, 57, 90, 136, 114, 207, 48, 46, 31, 90, 220, 18, 58, 143, 239, 111, 214, 27, 95, 6, 36, 53, 229, 62, 108, 45, 39, 1, 30, 47, 178, 56, 164, 206, 56, 42, 208, 46, 193, 61, 31, 147, 45, 147, 23, 187, 22, 50, 255, 111, 229, 132, 199, 152, 75, 142, 136, 209, 151, 2, 129, 129, 0, 165, 56, 232, 76, 55, 57, 240, 159, 92, 207, 220, 143, 130, 30, 57, 234, 251, 172, 171, 180, 54, 159, 229, 96, 246, 73, 112, 146, 75, 157, 242, 201, 161, 218, 37, 176, 35, 170, 50, 90, 148, 102, 191, 199, 239, 174, 78, 72, 67, 85, 199, 45, 149, 145, 132, 161, 212, 33, 157, 75, 216, 79, 39, 233, 18, 210, 255, 26, 72, 229, 239, 44, 12, 147, 158, 176, 192, 95, 126, 32, 175, 23, 226, 131, 139, 197, 175, 193, 62, 8, 151, 252, 68, 154, 94, 89, 189, 125, 90, 30, 36, 175, 73, 230, 194, 13, 233, 247, 123, 60, 241, 47, 171, 51, 189, 112, 111, 213, 141, 89, 70, 249, 236, 63, 236, 110, 115, 208]}; */ + export default new CryptoManager(); diff --git a/src/cryptoManager/HandShakeProtocol.js b/src/cryptoManager/HandShakeProtocol.js new file mode 100644 index 00000000..f57ce1f3 --- /dev/null +++ b/src/cryptoManager/HandShakeProtocol.js @@ -0,0 +1,450 @@ +import * as logger from 'loglevel'; +let log = logger.getLogger('CryptoManager'); + +import {chatkeysToStringCloner, encode, decode, decodeToUint8Array, parseToUint8Array, filterMessageToHash} from '../utils/utils.js'; + +class HandShakeProtocol { + + constructor(bus, chatKeys, crypto) { + this.bus = bus; + this.chatKeys = chatKeys; + this.crypto = crypto; + } + + startHandShake(message, chatKeys) { + let _this = this; + return new Promise(function(resolve, reject) { + chatKeys.keys.fromRandom = _this.crypto.generateRandom(); + let startHandShakeMsg = { + type: 'handshake', + to: message.to, + from: message.from, + body: { + handshakePhase: 'senderHello', + value: encode(chatKeys.keys.fromRandom) + } + }; + chatKeys.handshakeHistory.senderHello = filterMessageToHash(startHandShakeMsg, undefined, chatKeys.hypertyFrom.messageInfo); + + // check if was the encrypt or the mutual authentication that request the + // start of the handShakePhase. + + if (chatKeys.initialMessage) { + resolve({message: startHandShakeMsg, chatKeys: chatKeys}); + } else { + _this.chatKeys[message.from + '<->' + message.to] = chatKeys; + _this._messageBus.postMessage(startHandShakeMsg); + } + }); + } + + senderHello(message, chatKeys) { + let _this = this; + return new Promise(function(resolve, reject) { + log.log('senderHello'); + chatKeys.handshakeHistory.senderHello = filterMessageToHash(message); + chatKeys.keys.fromRandom = decodeToUint8Array(message.body.value); + chatKeys.keys.toRandom = _this.crypto.generateRandom(); + + let senderHelloMsg = { + type: 'handshake', + to: message.from, + from: message.to, + body: { + handshakePhase: 'receiverHello', + value: encode(chatKeys.keys.toRandom) + } + }; + chatKeys.handshakeHistory.receiverHello = filterMessageToHash(senderHelloMsg, undefined, chatKeys.hypertyFrom.messageInfo); + resolve({message: senderHelloMsg, chatKeys: chatKeys}); + }); + } + + receiverHello(message, chatKeys) { + let _this = this; + let value = {}; + let privateKeyHolder; + let iv; + return new Promise(function(resolve, reject) { + log.log('receiverHello'); + _this.getMyPrivateKey().then(privateKey =>{ + privateKeyHolder = privateKey; + + chatKeys.handshakeHistory.receiverHello = filterMessageToHash(message); + + return _this._idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain); + }).then((value) => { + + //TODO remove later this verification as soon as all the IdP proxy are updated in the example + let encodedpublicKey = (typeof value.contents === 'string') ? value.contents : value.contents.nonce; + + let receiverPublicKey = parseToUint8Array(encodedpublicKey); + let premasterSecret = _this.crypto.generatePMS(); + let toRandom = message.body.value; + chatKeys.hypertyTo.assertion = message.body.identity.assertion; + chatKeys.hypertyTo.publicKey = receiverPublicKey; + chatKeys.hypertyTo.userID = value.contents.email; + chatKeys.keys.toRandom = decodeToUint8Array(toRandom); + chatKeys.keys.premasterKey = premasterSecret; + + let concatKey = _this.crypto.concatPMSwithRandoms(premasterSecret, chatKeys.keys.toRandom, chatKeys.keys.fromRandom); + + return _this.crypto.generateMasterSecret(concatKey, 'messageHistoric' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); + + //generate the master key + }).then((masterKey) => { + chatKeys.keys.masterKey = masterKey; + + return _this.crypto.generateKeys(masterKey, 'key expansion' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); + + //generate the symmetric and hash keys + }).then((keys) => { + + chatKeys.keys.hypertyToSessionKey = new Uint8Array(keys[0]); + chatKeys.keys.hypertyFromSessionKey = new Uint8Array(keys[1]); + chatKeys.keys.hypertyToHashKey = new Uint8Array(keys[2]); + chatKeys.keys.hypertyFromHashKey = new Uint8Array(keys[3]); + iv = _this.crypto.generateIV(); + value.iv = encode(iv); + + let messageStructure = { + type: 'handshake', + to: message.from, + from: message.to, + body: { + handshakePhase: 'senderCertificate' + } + }; + + // hash the value and the iv + let filteredMessage = filterMessageToHash(messageStructure, 'ok' + iv, chatKeys.hypertyFrom.messageInfo); + return _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage); + }).then((hash) => { + value.hash = encode(hash); + + //encrypt the data + return _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, 'ok', iv); + }).then((encryptedData) => { + value.symetricEncryption = encode(encryptedData); + + return _this.crypto.encryptRSA(chatKeys.hypertyTo.publicKey, chatKeys.keys.premasterKey); + + }).then((encryptedValue) => { + value.assymetricEncryption = encode(encryptedValue); + + let messageStructure = { + type: 'handshake', + to: message.from, + from: message.to, + body: { + handshakePhase: 'senderCertificate' + } + }; + + let messageToHash = filterMessageToHash(messageStructure, chatKeys.keys.premasterKey, chatKeys.hypertyFrom.messageInfo); + return _this.crypto.signRSA(privateKeyHolder, encode(chatKeys.handshakeHistory) + encode(messageToHash)); + }).then(signature => { + + value.signature = encode(signature); + + let receiverHelloMsg = { + type: 'handshake', + to: message.from, + from: message.to, + body: { + handshakePhase: 'senderCertificate', + value: encode(value) + } + }; + chatKeys.handshakeHistory.senderCertificate = filterMessageToHash(receiverHelloMsg, 'ok' + iv, chatKeys.hypertyFrom.messageInfo); + + resolve({message: receiverHelloMsg, chatKeys: chatKeys}); + + }, error => reject(error)); + }); + } + + + senderCertificate(message, chatKeys) { + let _this = this; + let iv; + let filteredMessage; + let privateKeyHolder; + let value = {}; + return new Promise(function(resolve, reject) { + log.log('senderCertificate'); + + let receivedValue = decode(message.body.value); + + _this.getMyPrivateKey().then(privateKey =>{ + privateKeyHolder = privateKey; + + return _this._idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain); + }).then((value) => { + let encryptedPMS = decodeToUint8Array(receivedValue.assymetricEncryption); + + //TODO remove later this verification as soon as all the IdP proxy are updated in the example + let encodedpublicKey = (typeof value.contents === 'string') ? value.contents : value.contents.nonce; + + let senderPublicKey = parseToUint8Array(encodedpublicKey); + chatKeys.hypertyTo.assertion = message.body.identity.assertion; + chatKeys.hypertyTo.publicKey = senderPublicKey; + chatKeys.hypertyTo.userID = value.contents.email; + + return _this.crypto.decryptRSA(privateKeyHolder, encryptedPMS); + + }, (error) => { + // log.log(error); + reject('Error during authentication of identity: ', error.message); + + //obtain the PremasterKey using the private key + }).then(pms => { + + chatKeys.keys.premasterKey = new Uint8Array(pms); + + let signature = decodeToUint8Array(receivedValue.signature); + + let receivedmsgToHash = filterMessageToHash(message, chatKeys.keys.premasterKey); + + return _this.crypto.verifyRSA(chatKeys.hypertyTo.publicKey, encode(chatKeys.handshakeHistory) + encode(receivedmsgToHash), signature); + + // validates the signature received + }).then(signValidationResult => { + + log.log('SenderCertificate - signature validation result ', signValidationResult); + let concatKey = _this.crypto.concatPMSwithRandoms(chatKeys.keys.premasterKey, chatKeys.keys.toRandom, chatKeys.keys.fromRandom); + + return _this.crypto.generateMasterSecret(concatKey, 'messageHistoric' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); + + // generates the master keys from the Premaster key and the randoms + }).then(masterKey => { + chatKeys.keys.masterKey = masterKey; + + return _this.crypto.generateKeys(masterKey, 'key expansion' + chatKeys.keys.toRandom + chatKeys.keys.fromRandom); + + // generates the symmetric keys to be used in the symmetric encryption + }).then(keys => { + chatKeys.keys.hypertyFromSessionKey = new Uint8Array(keys[0]); + chatKeys.keys.hypertyToSessionKey = new Uint8Array(keys[1]); + chatKeys.keys.hypertyFromHashKey = new Uint8Array(keys[2]); + chatKeys.keys.hypertyToHashKey = new Uint8Array(keys[3]); + iv = decodeToUint8Array(receivedValue.iv); + let data = decodeToUint8Array(receivedValue.symetricEncryption); + + return _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv); + + }).then(decryptedData => { + // log.log('decryptedData', decryptedData); + + chatKeys.handshakeHistory.senderCertificate = filterMessageToHash(message, decryptedData + iv); + + let hashReceived = decodeToUint8Array(receivedValue.hash); + + filteredMessage = filterMessageToHash(message, decryptedData + iv); + + return _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hashReceived); + + }).then(verifiedHash => { + + // log.log('result of hash verification ', verifiedHash); + let receiverFinishedMessage = { + type: 'handshake', + to: message.from, + from: message.to, + body: { + handshakePhase: 'receiverFinishedMessage' + } + }; + iv = _this.crypto.generateIV(); + value.iv = encode(iv); + + filteredMessage = filterMessageToHash(receiverFinishedMessage, 'ok!' + iv, chatKeys.hypertyFrom.messageInfo); + + return _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage); + }).then(hash => { + + value.hash = encode(hash); + return _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, 'ok!', iv); + + }).then(encryptedValue => { + value.value = encode(encryptedValue); + let receiverFinishedMessage = { + type: 'handshake', + to: message.from, + from: message.to, + body: { + handshakePhase: 'receiverFinishedMessage', + value: encode(value) + } + }; + + chatKeys.handshakeHistory.receiverFinishedMessage = filterMessageToHash(receiverFinishedMessage, 'ok!' + iv, chatKeys.hypertyFrom.messageInfo); + chatKeys.authenticated = true; + resolve({message: receiverFinishedMessage, chatKeys: chatKeys}); + }).catch(err => { + reject('On _doHandShakePhase from senderCertificate error: ' + err); + }); + }); + } + + receiverFinishedMessage(message, chatKeys) { + + let _this = this; + let iv; + let value; + let hash; + return new Promise(function(resolve, reject) { + + log.log('receiverFinishedMessage'); + + chatKeys.authenticated = true; + + value = decode(message.body.value); + + iv = decodeToUint8Array(value.iv); + let data = decodeToUint8Array(value.value); + hash = decodeToUint8Array(value.hash); + + _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { + // log.log('decryptedData', decryptedData); + chatKeys.handshakeHistory.receiverFinishedMessage = filterMessageToHash(message, decryptedData + iv); + + let filteredMessage = filterMessageToHash(message, decryptedData + iv); + _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { + + // check if there was an initial message that was blocked and send it + if (chatKeys.initialMessage) { + + let initialMessage = { + type: 'create', + to: message.from, + from: message.to, + body: { + value: chatKeys.initialMessage.body.value + } + }; + + resolve({message: initialMessage, chatKeys: chatKeys}); + + //sends the sessionKey to the subscriber hyperty + } else { + _this._sendReporterSessionKey(message, chatKeys).then(value => { + + resolve(value); + }).catch(err => { + reject('On _doHandShakePhase from receiverFinishedMessage error: ' + err); + }); + } + }); + }); + }); + } + + reporterSessionKey(message, chatKeys) { + + let _this = this; + let iv; + let value; + let hash; + return new Promise(function(resolve, reject) { + + + log.log('reporterSessionKey'); + + let valueIVandHash = decode(message.body.value); + hash = decodeToUint8Array(valueIVandHash.hash); + iv = decodeToUint8Array(valueIVandHash.iv); + let encryptedValue = decodeToUint8Array(valueIVandHash.value); + let parsedValue; + let sessionKey; + let dataObjectURL; + let receiverAcknowledgeMsg; + + //log.log('[IdentityModule reporterSessionKey] - decryptAES: ', chatKeys.keys.hypertyToSessionKey, encryptedValue, iv); + + _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, encryptedValue, iv).then(decryptedValue => { + + parsedValue = decode(decryptedValue); + sessionKey = decodeToUint8Array(parsedValue.value); + dataObjectURL = parsedValue.dataObjectURL; + + let messageToHash = filterMessageToHash(message, decryptedValue + iv); + + return _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, messageToHash, hash); + + }).then(hashResult => { + + + // log.log('hash successfully validated ', hashResult); + + _this.dataObjectSessionKeys[dataObjectURL] = {sessionKey: sessionKey, isToEncrypt: true}; + let dataObjectSessionKeysClone = chatkeysToStringCloner(_this.dataObjectSessionKeys); + _this.storageManager.set('dataObjectSessionKeys', 0, dataObjectSessionKeysClone).catch(err => { + reject('On _sendReporterSessionKey from method reporterSessionKey error: ' + err); + }); + + iv = _this.crypto.generateIV(); + value.iv = encode(iv); + + return _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, 'ok!!', iv); + }).then(encryptedValue => { + + receiverAcknowledgeMsg = { + type: 'handshake', + to: message.from, + from: message.to, + body: { + handshakePhase: 'receiverAcknowledge' + } + }; + + value.value = encode(encryptedValue); + let messageToHash = filterMessageToHash(receiverAcknowledgeMsg, 'ok!!' + iv, chatKeys.hypertyFrom.messageInfo); + + return _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, messageToHash); + }).then(hashedMessage => { + let finalValue = encode({value: value.value, hash: encode(hashedMessage), iv: value.iv}); + + receiverAcknowledgeMsg.body.value = finalValue; + resolve({message: receiverAcknowledgeMsg, chatKeys: chatKeys}); + }).catch(err => { + reject('On _doHandShakePhase from reporterSessionKey error: ' + err); + }); + }); + } + + + receiverAcknowledge(message, chatKeys) { + + let _this = this; + let iv; + return new Promise(function(resolve, reject) { + + log.log('receiverAcknowledge'); + + let receivedvalueIVandHash = decode(message.body.value); + let receivedHash = decodeToUint8Array(receivedvalueIVandHash.hash); + iv = decodeToUint8Array(receivedvalueIVandHash.iv); + let receivedEncryptedValue = decodeToUint8Array(receivedvalueIVandHash.value); + + _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, receivedEncryptedValue, iv).then(decryptedValue => { + + let filteredMessage = filterMessageToHash(message, decryptedValue + iv); + return _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, receivedHash); + }).then(hashResult => { + // log.log('hashResult ', hashResult); + + let callback = chatKeys.callback; + + if (callback) { + callback('handShakeEnd'); + } + resolve('handShakeEnd'); + }).catch(err => { + reject('On _doHandShakePhase from receiverAcknowledge error: ' + err); + }); + }); + } +} + +export default HandShakeProtocol; diff --git a/src/identity/IdentityManager.js b/src/identity/IdentityManager.js index d67bedaa..88951610 100755 --- a/src/identity/IdentityManager.js +++ b/src/identity/IdentityManager.js @@ -42,15 +42,16 @@ class IdentityManager { processMessage(message) { log.log('[IdentityManager.processMessage] ', message); - return new Promise((resolve,reject) => { + return new Promise((resolve, reject) => { // skip messages that don't need identity tokens in the body if (!this._isToSetID(message)) return resolve(message); let from = message.from; - let sourceURL = undefined; - if ( message.hasOwnProperty('body') && message.body.hasOwnProperty('source')) { + + //let sourceURL = undefined; + if (message.hasOwnProperty('body') && message.body.hasOwnProperty('source')) { from = message.body.source; } diff --git a/src/identity/IdentityModule.js b/src/identity/IdentityModule.js index 94316d69..369ac871 100755 --- a/src/identity/IdentityModule.js +++ b/src/identity/IdentityModule.js @@ -285,7 +285,7 @@ class IdentityModule { log.log('[IdentityModule] Identity selected by hyperty.'); return resolve(assertion); }, (err) => { // if it got an error then just select identity from GUI - // log.error('[IdentityModule] Could not select identity from hyperty.'); + log.error('[IdentityModule] Could not select identity from hyperty:', err); _this.selectIdentityFromGUI().then((newAssertion) => { log.log('[IdentityModule] Identity selected by hyperty.'); return resolve(newAssertion); diff --git a/src/utils/utils.js b/src/utils/utils.js index 754f860b..02950559 100755 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -63,13 +63,13 @@ export function divideURL(url) { return result; } - // check if the url has the scheme and includes an @ + // check if the url has the scheme and includes an @ if (parts[0] === url && parts[0].includes('@')) { let scheme = parts[0] === url ? 'smtp' : parts[0]; parts = recurse(scheme + '://' + parts[0]); } - // if the domain includes an @, divide it to domain and identity respectively + // if the domain includes an @, divide it to domain and identity respectively if (parts[1].includes('@')) { parts[2] = parts[0] + '://' + parts[1]; parts[1] = parts[1].substr(parts[1].indexOf('@') + 1); @@ -558,7 +558,7 @@ export function parse(value) { } catch (err) { console.error('[Utils.parse:err]' + err); console.trace(); - console.error('That that cause the error:', value); + console.error('The value that cause the error:', value); throw err; } } @@ -576,3 +576,23 @@ export function parseToUint8Array(value) { throw err; } } + +/** + * filter the messages to hash, by removing some fields not generated by the runtime core + * @param {Message} message message + * @param {String} decryptedValue (Optional) value from body.value in case it originally comes encrypted + * @param {JSON} identity(Optional) add the hyperty identity associated in case is not added to the initial message + * @return {Message} new message filtered + */ +export function filterMessageToHash(message, decryptedValue, identity) { + return { + type: message.type, + from: message.from, + to: message.to, + body: { + identity: identity || message.body.identity, + value: decryptedValue || message.body.value, + handshakePhase: message.body.handshakePhase + } + }; +} From 452f3c1a22ed891e2ea95de342ca9877b19a4fc1 Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Fri, 29 Dec 2017 20:52:34 +0000 Subject: [PATCH 02/15] Handshake refactory --- src/cryptoManager/CryptoManager.js | 26 ++++-- src/cryptoManager/HandShakeProtocol.js | 18 ++--- src/cryptoManager/utf8.js | 106 ++++++++++++------------- 3 files changed, 74 insertions(+), 76 deletions(-) mode change 100644 => 100755 src/cryptoManager/HandShakeProtocol.js diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index 76d3c992..89c3fd15 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -44,12 +44,12 @@ class CryptoManager { _this._runtimeFactory = runtimeFactory; _this._domain = divideURL(_this._runtimeURL).domain; + _this.chatKeys = {}; _this.crypto = new Crypto(_this._runtimeFactory); - _this.handShakeProtocol = new HandShakeProtocol(_this.crypto); + _this.handShakeProtocol = new HandShakeProtocol(_this.chatKeys, _this.crypto); // hashTable to store all the crypto information between two hyperties - _this.chatKeys = {}; // hashTable to store the symmetric keys to be used in the chat group _this.dataObjectSessionKeys = {}; @@ -838,7 +838,13 @@ class CryptoManager { switch (handshakeType) { case 'startHandShake': - _this.handShakeProtocol.startHandShake(message, chatKeys).then(result => { resolve(result); }); + _this.handShakeProtocol.startHandShake(message, chatKeys).then(result => { + if (result.postToBus) { + _this._messageBus.postMessage(result.message); + } else { + resolve({message: result.message, chatKeys: result.chatKeys}); + } + }); break; case 'senderHello': @@ -855,11 +861,17 @@ class CryptoManager { .catch(err => { reject(err); }); break; - case 'receiverFinishedMessage': { - _this.handShakeProtocol.receiverFinishedMessage(message, chatKeys).then(result => { resolve(result); }) - .catch(err => { reject(err); }); + case 'receiverFinishedMessage': + _this.handShakeProtocol.receiverFinishedMessage(message, chatKeys).then(result => { + if (result.sendReporterSessionKey) { + _this._sendReporterSessionKey(result.message, result.chatKeys).then(value => { + resolve(value); + }); + } else { + resolve({message: result.message, chatKeys: result.chatKeys}); + } + }).catch(err => { reject(err); }); break; - } case 'reporterSessionKey': { _this.handShakeProtocol.reporterSessionKey(message, chatKeys).then(result => { resolve(result); }) diff --git a/src/cryptoManager/HandShakeProtocol.js b/src/cryptoManager/HandShakeProtocol.js old mode 100644 new mode 100755 index f57ce1f3..ed4b48d9 --- a/src/cryptoManager/HandShakeProtocol.js +++ b/src/cryptoManager/HandShakeProtocol.js @@ -5,13 +5,12 @@ import {chatkeysToStringCloner, encode, decode, decodeToUint8Array, parseToUint8 class HandShakeProtocol { - constructor(bus, chatKeys, crypto) { - this.bus = bus; + constructor(chatKeys, crypto) { this.chatKeys = chatKeys; this.crypto = crypto; } - startHandShake(message, chatKeys) { + startHandShake(message, chatKeys, messageBus) { let _this = this; return new Promise(function(resolve, reject) { chatKeys.keys.fromRandom = _this.crypto.generateRandom(); @@ -30,10 +29,10 @@ class HandShakeProtocol { // start of the handShakePhase. if (chatKeys.initialMessage) { - resolve({message: startHandShakeMsg, chatKeys: chatKeys}); + resolve({postToBus: false, message: startHandShakeMsg, chatKeys: chatKeys}); } else { _this.chatKeys[message.from + '<->' + message.to] = chatKeys; - _this._messageBus.postMessage(startHandShakeMsg); + resolve({postToBus: true, message: startHandShakeMsg}); } }); } @@ -324,16 +323,11 @@ class HandShakeProtocol { } }; - resolve({message: initialMessage, chatKeys: chatKeys}); + resolve({sendReporterSessionKey: false, message: initialMessage, chatKeys: chatKeys}); //sends the sessionKey to the subscriber hyperty } else { - _this._sendReporterSessionKey(message, chatKeys).then(value => { - - resolve(value); - }).catch(err => { - reject('On _doHandShakePhase from receiverFinishedMessage error: ' + err); - }); + resolve({sendReporterSessionKey: true, message: message, chatKeys: chatKeys}); } }); }); diff --git a/src/cryptoManager/utf8.js b/src/cryptoManager/utf8.js index 055a9736..f9421962 100755 --- a/src/cryptoManager/utf8.js +++ b/src/cryptoManager/utf8.js @@ -1,66 +1,58 @@ // Marshals a string to Uint8Array. export function encodeUTF8(s) { - var i = 0; - var bytes = new Uint8Array(s.length * 4); - for (var ci = 0; ci != s.length; ci++) { - try{ - var xxx = s.charCodeAt(ci); - } catch (err){ - console.log(err.message); - return; - + var i = 0; + var bytes = new Uint8Array(s.length * 4); + for (var ci = 0; ci != s.length; ci++) { + var c = s.charCodeAt(ci); + if (c < 128) { + bytes[i++] = c; + continue; + } + if (c < 2048) { + bytes[i++] = c >> 6 | 192; + } else { + if (c > 0xd7ff && c < 0xdc00) { + if (++ci == s.length) throw 'UTF-8 encode: incomplete surrogate pair'; + var c2 = s.charCodeAt(ci); + if (c2 < 0xdc00 || c2 > 0xdfff) throw 'UTF-8 encode: second char code 0x' + c2.toString(16) + ' at index ' + ci + ' in surrogate pair out of range'; + c = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff); + bytes[i++] = c >> 18 | 240; + bytes[i++] = c >> 12 & 63 | 128; + } else { // c <= 0xffff + bytes[i++] = c >> 12 | 224; + } + bytes[i++] = c >> 6 & 63 | 128; } - var c = s.charCodeAt(ci); - if (c < 128) { - bytes[i++] = c; - continue; - } - if (c < 2048) { - bytes[i++] = c >> 6 | 192; - } else { - if (c > 0xd7ff && c < 0xdc00) { - if (++ci == s.length) throw 'UTF-8 encode: incomplete surrogate pair'; - var c2 = s.charCodeAt(ci); - if (c2 < 0xdc00 || c2 > 0xdfff) throw 'UTF-8 encode: second char code 0x' + c2.toString(16) + ' at index ' + ci + ' in surrogate pair out of range'; - c = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff); - bytes[i++] = c >> 18 | 240; - bytes[i++] = c>> 12 & 63 | 128; - } else { // c <= 0xffff - bytes[i++] = c >> 12 | 224; - } - bytes[i++] = c >> 6 & 63 | 128; - } - bytes[i++] = c & 63 | 128; - } - return bytes.subarray(0, i); + bytes[i++] = c & 63 | 128; + } + return bytes.subarray(0, i); } // Unmarshals an Uint8Array to string. export function decodeUTF8(bytes) { - var s = ''; - var i = 0; - while (i < bytes.length) { - var c = bytes[i++]; - if (c > 127) { - if (c > 191 && c < 224) { - if (i >= bytes.length) throw 'UTF-8 decode: incomplete 2-byte sequence'; - c = (c & 31) << 6 | bytes[i] & 63; - } else if (c > 223 && c < 240) { - if (i + 1 >= bytes.length) throw 'UTF-8 decode: incomplete 3-byte sequence'; - c = (c & 15) << 12 | (bytes[i] & 63) << 6 | bytes[++i] & 63; - } else if (c > 239 && c < 248) { - if (i+2 >= bytes.length) throw 'UTF-8 decode: incomplete 4-byte sequence'; - c = (c & 7) << 18 | (bytes[i] & 63) << 12 | (bytes[++i] & 63) << 6 | bytes[++i] & 63; - } else throw 'UTF-8 decode: unknown multibyte start 0x' + c.toString(16) + ' at index ' + (i - 1); - ++i; - } + var s = ''; + var i = 0; + while (i < bytes.length) { + var c = bytes[i++]; + if (c > 127) { + if (c > 191 && c < 224) { + if (i >= bytes.length) throw 'UTF-8 decode: incomplete 2-byte sequence'; + c = (c & 31) << 6 | bytes[i] & 63; + } else if (c > 223 && c < 240) { + if (i + 1 >= bytes.length) throw 'UTF-8 decode: incomplete 3-byte sequence'; + c = (c & 15) << 12 | (bytes[i] & 63) << 6 | bytes[++i] & 63; + } else if (c > 239 && c < 248) { + if (i + 2 >= bytes.length) throw 'UTF-8 decode: incomplete 4-byte sequence'; + c = (c & 7) << 18 | (bytes[i] & 63) << 12 | (bytes[++i] & 63) << 6 | bytes[++i] & 63; + } else { throw 'UTF-8 decode: unknown multibyte start 0x' + c.toString(16) + ' at index ' + (i - 1); } + ++i; + } - if (c <= 0xffff) s += String.fromCharCode(c); - else if (c <= 0x10ffff) { - c -= 0x10000; - s += String.fromCharCode(c >> 10 | 0xd800) - s += String.fromCharCode(c & 0x3FF | 0xdc00) - } else throw 'UTF-8 decode: code point 0x' + c.toString(16) + ' exceeds UTF-16 reach'; - } - return s; + if (c <= 0xffff) { s += String.fromCharCode(c); } else if (c <= 0x10ffff) { + c -= 0x10000; + s += String.fromCharCode(c >> 10 | 0xd800); + s += String.fromCharCode(c & 0x3FF | 0xdc00); + } else { throw 'UTF-8 decode: code point 0x' + c.toString(16) + ' exceeds UTF-16 reach'; } + } + return s; } From 75b5588008009ddc01f0ece266fc0f1cd796cfc1 Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Wed, 3 Jan 2018 16:03:21 +0000 Subject: [PATCH 03/15] working doHandShake refactory --- src/cryptoManager/CryptoManager.js | 25 +++++++-------- src/cryptoManager/HandShakeProtocol.js | 44 +++++++++++++------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index 83ec1ef1..3edcb342 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -45,23 +45,18 @@ class CryptoManager { _this._runtimeFactory = runtimeFactory; _this._domain = divideURL(_this._runtimeURL).domain; _this.chatKeys = {}; + _this._idm = idm; - _this.crypto = new Crypto(_this._runtimeFactory); - _this.handShakeProtocol = new HandShakeProtocol(_this.chatKeys, _this.crypto); - - // hashTable to store all the crypto information between two hyperties - - // hashTable to store the symmetric keys to be used in the chat group _this.dataObjectSessionKeys = {}; + _this.crypto = new Crypto(_this._runtimeFactory); + _this.handShakeProtocol = new HandShakeProtocol(_this.chatKeys, _this.crypto, _this._idm, + _this.dataObjectSessionKeys, _this.storageManager); //failsafe to enable/disable all the criptographic functions _this.isToUseEncryption = true; _this._registry = registry; _this._coreDiscovery = coreDiscovery; - - _this._idm = idm; - } //******************* GET AND SET METHODS ******************* @@ -853,13 +848,17 @@ class CryptoManager { break; case 'receiverHello': - _this.handShakeProtocol.receiverHello(message, chatKeys).then(result => { resolve(result); }) - .catch(err => { reject(err); }); + _this.getMyPrivateKey().then(privateKey =>{ + _this.handShakeProtocol.receiverHello(message, chatKeys, privateKey).then(result => { resolve(result); }) + .catch(err => { reject(err); }); + }); break; case 'senderCertificate': - _this.handShakeProtocol.senderCertificate(message, chatKeys).then(result => { resolve(result); }) - .catch(err => { reject(err); }); + _this.getMyPrivateKey().then(privateKey =>{ + _this.handShakeProtocol.senderCertificate(message, chatKeys, privateKey).then(result => { resolve(result); }) + .catch(err => { reject(err); }); + }); break; case 'receiverFinishedMessage': diff --git a/src/cryptoManager/HandShakeProtocol.js b/src/cryptoManager/HandShakeProtocol.js index ed4b48d9..43766477 100755 --- a/src/cryptoManager/HandShakeProtocol.js +++ b/src/cryptoManager/HandShakeProtocol.js @@ -1,16 +1,26 @@ import * as logger from 'loglevel'; let log = logger.getLogger('CryptoManager'); -import {chatkeysToStringCloner, encode, decode, decodeToUint8Array, parseToUint8Array, filterMessageToHash} from '../utils/utils.js'; +import {chatkeysToStringCloner, encode, decode, decodeToUint8Array, + parseToUint8Array, filterMessageToHash} from '../utils/utils.js'; + +/** +* This class contains the handshake protocol, used to exchange session keys between +* two user, after their identity is validate. +* +*/ class HandShakeProtocol { - constructor(chatKeys, crypto) { + constructor(chatKeys, crypto, idm, sessionKeys, storage) { this.chatKeys = chatKeys; this.crypto = crypto; + this.idm = idm; + this.dataObjectSessionKeys = sessionKeys; + this.storageManager = storage; } - startHandShake(message, chatKeys, messageBus) { + startHandShake(message, chatKeys) { let _this = this; return new Promise(function(resolve, reject) { chatKeys.keys.fromRandom = _this.crypto.generateRandom(); @@ -59,20 +69,15 @@ class HandShakeProtocol { }); } - receiverHello(message, chatKeys) { + receiverHello(message, chatKeys, privateKey) { let _this = this; let value = {}; - let privateKeyHolder; let iv; return new Promise(function(resolve, reject) { log.log('receiverHello'); - _this.getMyPrivateKey().then(privateKey =>{ - privateKeyHolder = privateKey; - - chatKeys.handshakeHistory.receiverHello = filterMessageToHash(message); + chatKeys.handshakeHistory.receiverHello = filterMessageToHash(message); - return _this._idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain); - }).then((value) => { + _this.idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain).then((value) => { //TODO remove later this verification as soon as all the IdP proxy are updated in the example let encodedpublicKey = (typeof value.contents === 'string') ? value.contents : value.contents.nonce; @@ -141,7 +146,7 @@ class HandShakeProtocol { }; let messageToHash = filterMessageToHash(messageStructure, chatKeys.keys.premasterKey, chatKeys.hypertyFrom.messageInfo); - return _this.crypto.signRSA(privateKeyHolder, encode(chatKeys.handshakeHistory) + encode(messageToHash)); + return _this.crypto.signRSA(privateKey, encode(chatKeys.handshakeHistory) + encode(messageToHash)); }).then(signature => { value.signature = encode(signature); @@ -164,22 +169,17 @@ class HandShakeProtocol { } - senderCertificate(message, chatKeys) { + senderCertificate(message, chatKeys, privateKey) { let _this = this; let iv; let filteredMessage; - let privateKeyHolder; let value = {}; return new Promise(function(resolve, reject) { log.log('senderCertificate'); let receivedValue = decode(message.body.value); - _this.getMyPrivateKey().then(privateKey =>{ - privateKeyHolder = privateKey; - - return _this._idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain); - }).then((value) => { + _this.idm.validateAssertion(message.body.identity.assertion, undefined, message.body.identity.idp.domain).then((value) => { let encryptedPMS = decodeToUint8Array(receivedValue.assymetricEncryption); //TODO remove later this verification as soon as all the IdP proxy are updated in the example @@ -190,7 +190,7 @@ class HandShakeProtocol { chatKeys.hypertyTo.publicKey = senderPublicKey; chatKeys.hypertyTo.userID = value.contents.email; - return _this.crypto.decryptRSA(privateKeyHolder, encryptedPMS); + return _this.crypto.decryptRSA(privateKey, encryptedPMS); }, (error) => { // log.log(error); @@ -290,7 +290,7 @@ class HandShakeProtocol { let _this = this; let iv; - let value; + let value = {}; let hash; return new Promise(function(resolve, reject) { @@ -338,7 +338,7 @@ class HandShakeProtocol { let _this = this; let iv; - let value; + let value = {}; let hash; return new Promise(function(resolve, reject) { From 931636cd4bf8497c6d479196d225df348f0e08b6 Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Mon, 8 Jan 2018 15:23:46 +0000 Subject: [PATCH 04/15] changed run.sh --- run.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run.sh b/run.sh index cbcf7c30..355097df 100755 --- a/run.sh +++ b/run.sh @@ -1,2 +1,4 @@ npm run build:dev cp ./dist/Runtime.js ../dev-hyperty-toolkit/resources +cp ./dist/Runtime.js ../dev-runtime-nodejs/node_modules/runtime-core/dist + From 1ad433d89ea643eaeb2d5f06f04d580f15cbc62f Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Wed, 24 Jan 2018 15:44:48 +0000 Subject: [PATCH 05/15] Crypto refactory --- package-lock.json | 0 src/cryptoManager/CryptoManager.js | 184 +++--- src/cryptoManager/HandShakeProtocol.js | 3 +- .../MessageEncryptionHandling.js | 573 ++++++++++++++++++ test/HypertyResourceStorage.spec.js | 0 test/resources/generateData.js | 0 6 files changed, 650 insertions(+), 110 deletions(-) mode change 100644 => 100755 package-lock.json create mode 100755 src/cryptoManager/MessageEncryptionHandling.js mode change 100644 => 100755 test/HypertyResourceStorage.spec.js mode change 100644 => 100755 test/resources/generateData.js diff --git a/package-lock.json b/package-lock.json old mode 100644 new mode 100755 diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index 6904085d..1b6ea96b 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -5,6 +5,7 @@ import HandShakeProtocol from './HandShakeProtocol'; import {divideURL, isDataObjectURL, isLegacy, chatkeysToStringCloner, chatkeysToArrayCloner, parseMessageURL, parse, stringify, encode, decode, decodeToUint8Array, filterMessageToHash} from '../utils/utils.js'; +//import MessageEncryptionHandling from './MessageEncryptionHandling.js'; import Crypto from './Crypto'; @@ -50,13 +51,15 @@ class CryptoManager { _this.dataObjectSessionKeys = {}; _this.crypto = new Crypto(_this._runtimeFactory); _this.handShakeProtocol = new HandShakeProtocol(_this.chatKeys, _this.crypto, _this._idm, - _this.dataObjectSessionKeys, _this.storageManager); + _this.dataObjectSessionKeys, _this.storageManager); //failsafe to enable/disable all the criptographic functions _this.isToUseEncryption = true; _this._registry = registry; _this._coreDiscovery = coreDiscovery; + + // _this._messageEncryptionHandling = new MessageEncryptionHandling(registry, _this.chatKeys, _this.crypto, this._idm); } //******************* GET AND SET METHODS ******************* @@ -175,71 +178,6 @@ class CryptoManager { //******************* ENCRYPTION METHODS ******************* - /** -* Identifies the messages to be encrypted -* @param {Message} message -* @returns {boolean} returns true if the message requires encryption -*/ - - _isToEncrypt(message) { - log.info('[CryptoManager.istoChyperModule]', message); - let isCreate = message.type === 'create'; - let isFromHyperty = message.from.includes('hyperty://'); - let isToHyperty = message.to.includes('hyperty://'); - let isToDataObject = isDataObjectURL(message.to); - - let doMutualAuthentication = message.body.hasOwnProperty('mutual') ? message.body.mutual : true; - - if (!doMutualAuthentication) return false; - - //if is not to apply encryption, then returns resolve - if (!this.isToUseEncryption && !(message.type === 'handshake')) { - log.info('not handshake: encryption disabled'); - return false; - } - - if (message.type === 'update') { - log.info('update:encryption disabled'); - return false; - } - - if (isLegacy(message.to)) return false; - - return ((isCreate && isFromHyperty && isToHyperty) || (isCreate && isFromHyperty && isToDataObject && doMutualAuthentication) || message.type === 'handshake' || (message.type === 'update' && doMutualAuthentication)); - } - - - _isToDecrypt(message) { - let _this = this; - - - return new Promise((resolve, reject) => { - // For sybscribe message let's start the mutualAuthentication - let isSubscription = message.type === 'subscribe'; - let isFromRemoteSM = _this._isFromRemoteSM(message.from); - - if (isSubscription & isFromRemoteSM) { - log.log('_doMutualAuthenticationPhase1'); - - _this._doMutualAuthenticationPhase1(message).then(() => { - resolve(false); - }, (error) => { - reject(error); - }); - - } else if (message.hasOwnProperty('body') && message.body.hasOwnProperty('value') && typeof message.body.value === 'string') { - log.log('_isToDecrypt:true'); - resolve(true); - } else { - log.log('_isToDecrypt:false'); - resolve(false); - } - - }).catch((error) => { - log.error('[CryptoManager._isToDecrypt]', error); - }); - - } encryptMessage(message) { //log.info('encryptMessage:message', message); @@ -249,8 +187,6 @@ class CryptoManager { return new Promise(function(resolve, reject) { - let isHandShakeType = message.type === 'handshake'; - //if is not to apply encryption, then returns resolve if (!_this._isToEncrypt(message)) { // log.log('decryption disabled'); @@ -269,56 +205,23 @@ class CryptoManager { return resolve(message); } + //------------> Needs tests! if (isToLegacyIdentity) { resolve(message); } else if (isFromHyperty && isToHyperty) { - let userURL = _this._registry.getHypertyOwner(message.from); - if (userURL) { - - // check if exists any keys between two users - let chatKeys = _this.chatKeys[message.from + '<->' + message.to]; - if (!chatKeys) { - chatKeys = _this._newChatCrypto(message, userURL); - - //log.log('createChatKey encrypt', message.from + message.to); - _this.chatKeys[message.from + '<->' + message.to] = chatKeys; - message.body.handshakePhase = 'startHandShake'; - } - - if (chatKeys.authenticated && !isHandShakeType) { - - let iv = _this.crypto.generateIV(); - _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, stringify(message.body.value), iv).then(encryptedValue => { - - let filteredMessage = filterMessageToHash(message, stringify(message.body.value) + - stringify(iv), chatKeys.hypertyFrom.messageInfo); - - _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { - //log.log('result of hash ', hash); - let value = {iv: encode(iv), value: encode(encryptedValue), hash: encode(hash)}; - message.body.value = encode(value); - - resolve(message); - }); - }); - - // if is a handshake message, just resolve it - } else if (isHandShakeType) { - resolve(message); - - // else, starts a new handshake protocol + /* _this._messageEncryptionHandling.betweenHyperties(message).then(result => { + if (result.isHandShakeNeeded) { + resolve(result.message); } else { - _this._doHandShakePhase(message, chatKeys).then(function(value) { + _this._doHandShakePhase(result.message, _this.chatKeys).then(function(value) { _this.chatKeys[message.from + '<->' + message.to] = value.chatKeys; _this._messageBus.postMessage(value.message); reject('encrypt handshake protocol phase '); }); } - } else { - reject('In encryptMessage: Hyperty owner URL was not found'); - } - + }); +*/ //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { @@ -1031,6 +934,71 @@ class CryptoManager { }); } + + _isToDecrypt(message) { + let _this = this; + + return new Promise((resolve, reject) => { + // For sybscribe message let's start the mutualAuthentication + let isSubscription = message.type === 'subscribe'; + let isFromRemoteSM = _this._isFromRemoteSM(message.from); + + if (isSubscription & isFromRemoteSM) { + log.log('_doMutualAuthenticationPhase1'); + + _this._doMutualAuthenticationPhase1(message).then(() => { + resolve(false); + }, (error) => { + reject(error); + }); + + } else if (message.hasOwnProperty('body') && message.body.hasOwnProperty('value') && typeof message.body.value === 'string') { + log.log('_isToDecrypt:true'); + resolve(true); + } else { + log.log('_isToDecrypt:false'); + resolve(false); + } + + }).catch((error) => { + log.error('[CryptoManager._isToDecrypt]', error); + }); + + } + + /** + * Identifies the messages to be encrypted + * @param {Message} message + * @returns {boolean} returns true if the message requires encryption + */ + + _isToEncrypt(message) { + log.info('[CryptoManager.istoChyperModule]', message); + let isCreate = message.type === 'create'; + let isFromHyperty = message.from.includes('hyperty://'); + let isToHyperty = message.to.includes('hyperty://'); + let isToDataObject = isDataObjectURL(message.to); + + let doMutualAuthentication = message.body.hasOwnProperty('mutual') ? message.body.mutual : true; + + if (!doMutualAuthentication) return false; + + //if is not to apply encryption, then returns resolve + if (!this.isToUseEncryption && !(message.type === 'handshake')) { + log.info('not handshake: encryption disabled'); + return false; + } + + if (message.type === 'update') { + log.info('update:encryption disabled'); + return false; + } + + if (isLegacy(message.to)) return false; + + return ((isCreate && isFromHyperty && isToHyperty) || (isCreate && isFromHyperty && isToDataObject && doMutualAuthentication) || message.type === 'handshake' || (message.type === 'update' && doMutualAuthentication)); + } + } /* diff --git a/src/cryptoManager/HandShakeProtocol.js b/src/cryptoManager/HandShakeProtocol.js index 43766477..7712bc76 100755 --- a/src/cryptoManager/HandShakeProtocol.js +++ b/src/cryptoManager/HandShakeProtocol.js @@ -8,7 +8,6 @@ import {chatkeysToStringCloner, encode, decode, decodeToUint8Array, /** * This class contains the handshake protocol, used to exchange session keys between * two user, after their identity is validate. -* */ class HandShakeProtocol { @@ -290,7 +289,7 @@ class HandShakeProtocol { let _this = this; let iv; - let value = {}; + let value = {}; let hash; return new Promise(function(resolve, reject) { diff --git a/src/cryptoManager/MessageEncryptionHandling.js b/src/cryptoManager/MessageEncryptionHandling.js new file mode 100755 index 00000000..f2b42a8e --- /dev/null +++ b/src/cryptoManager/MessageEncryptionHandling.js @@ -0,0 +1,573 @@ +import {divideURL, isDataObjectURL, isLegacy, chatkeysToStringCloner, chatkeysToArrayCloner, parseMessageURL, + parse, stringify, encode, decode, decodeToUint8Array, filterMessageToHash} from '../utils/utils.js'; + + +class MessageEncryptionHandling { + + constructor(registry, chatKeys, crypto, idm) { + this.registry = registry; + this.chatKeys = chatKeys; + this.crypto = crypto; + this.idm = idm; + } + + betweenHyperties(message) { + let _this = this; + + return new Promise((resolve, reject) => { + + let userURL = _this.registry.getHypertyOwner(message.from); + let isHandShakeType = message.type === 'handshake'; + if (userURL) { + + // check if exists any keys between two users + let chatKeys = _this.chatKeys[message.from + '<->' + message.to]; + if (!chatKeys) { + chatKeys = _this._newChatCrypto(message, userURL); + + //log.log('createChatKey encrypt', message.from + message.to); + _this.chatKeys[message.from + '<->' + message.to] = chatKeys; + message.body.handshakePhase = 'startHandShake'; + } + + if (chatKeys.authenticated && !isHandShakeType) { + + let iv = _this.crypto.generateIV(); + _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, stringify(message.body.value), iv).then(encryptedValue => { + + let filteredMessage = filterMessageToHash(message, stringify(message.body.value) + + stringify(iv), chatKeys.hypertyFrom.messageInfo); + + _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { + //log.log('result of hash ', hash); + let value = {iv: encode(iv), value: encode(encryptedValue), hash: encode(hash)}; + message.body.value = encode(value); + + resolve({ message: message, isHandShakeNeeded: false}); + }); + }); + + // if is a handshake message, just resolve it + } else if (isHandShakeType) { + resolve({ message: message, isHandShakeNeeded: false}); + + // else, starts a new handshake protocol + } else { + resolve({ message: message, isHandShakeNeeded: true}); + + /* + _this._doHandShakePhase(message, chatKeys).then(function(value) { + _this.chatKeys[message.from + '<->' + message.to] = value.chatKeys; + + _this._messageBus.postMessage(value.message); + reject('encrypt handshake protocol phase '); + }); + */ + } + } else { + reject('In encryptMessage: Hyperty owner URL was not found'); + } + }); + } + + /* + encryptMessage(message) { + //log.info('encryptMessage:message', message); + let _this = this; + + log.log('encrypt message '); + + return new Promise(function(resolve, reject) { + + let isHandShakeType = message.type === 'handshake'; + + //if is not to apply encryption, then returns resolve + if (!_this._isToEncrypt(message)) { + // log.log('decryption disabled'); + return resolve(message); + } + + let dataObjectURL = parseMessageURL(message.to); + + let isToDataObject = isDataObjectURL(dataObjectURL); + let isToLegacyIdentity = isLegacy(message.to); + let isFromHyperty = divideURL(message.from).type === 'hyperty'; + let isToHyperty = divideURL(message.to).type === 'hyperty'; + + if (message.type === 'update') { + log.log('encrypt message: message type update'); + return resolve(message); + } + + if (isToLegacyIdentity) { + resolve(message); + } else if (isFromHyperty && isToHyperty) { + let userURL = _this.registry.getHypertyOwner(message.from); + if (userURL) { + + // check if exists any keys between two users + let chatKeys = _this.chatKeys[message.from + '<->' + message.to]; + if (!chatKeys) { + chatKeys = _this._newChatCrypto(message, userURL); + + //log.log('createChatKey encrypt', message.from + message.to); + _this.chatKeys[message.from + '<->' + message.to] = chatKeys; + message.body.handshakePhase = 'startHandShake'; + } + + if (chatKeys.authenticated && !isHandShakeType) { + + let iv = _this.crypto.generateIV(); + _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, stringify(message.body.value), iv).then(encryptedValue => { + + let filteredMessage = filterMessageToHash(message, stringify(message.body.value) + + stringify(iv), chatKeys.hypertyFrom.messageInfo); + + _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { + //log.log('result of hash ', hash); + let value = {iv: encode(iv), value: encode(encryptedValue), hash: encode(hash)}; + message.body.value = encode(value); + + resolve(message); + }); + }); + + // if is a handshake message, just resolve it + } else if (isHandShakeType) { + resolve(message); + + // else, starts a new handshake protocol + } else { + _this._doHandShakePhase(message, chatKeys).then(function(value) { + _this.chatKeys[message.from + '<->' + message.to] = value.chatKeys; + + _this._messageBus.postMessage(value.message); + reject('encrypt handshake protocol phase '); + }); + } + } else { + reject('In encryptMessage: Hyperty owner URL was not found'); + } + + //if from hyperty to a dataObjectURL + } else if (isFromHyperty && isToDataObject) { + + //log.log('dataObject value to encrypt: ', message.body.value); + //log.log('IdentityModule - encrypt from hyperty to dataobject ', message); + + _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { + sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); + let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; + + _this.dataObjectsStorage.getDataObject(dataObjectURL).then((isHypertyReporter) => { + //if no key exists, create a new one if is the reporter of dataObject + if (!dataObjectKey) { + // if the hyperty is the reporter of the dataObject then generates a session key + if (isHypertyReporter.reporter && isHypertyReporter.reporter === message.from) { + + let sessionKey = _this.crypto.generateRandom(); + _this.dataObjectSessionKeys[dataObjectURL] = {sessionKey: sessionKey, isToEncrypt: true}; + let dataObjectSessionKeysClone = chatkeysToStringCloner(_this.dataObjectSessionKeys); + + //TODO: check if this does not need to be stored + _this.storageManager.set('dataObjectSessionKeys', 0, dataObjectSessionKeysClone).catch(err => { + reject('On encryptMessage from method storageManager.set error: ' + err); + }); + dataObjectKey = _this.dataObjectSessionKeys[dataObjectURL]; + } + } + + //check if there is already a session key for the chat room + if (dataObjectKey) { + + // and if is to apply encryption, encrypt the messages + if (dataObjectKey.isToEncrypt) { + let iv = _this.crypto.generateIV(); + let stringifiedIV = stringify(iv); + let stringifiedMessageBody = stringify(message.body.value); + + _this.crypto.encryptAES(dataObjectKey.sessionKey, stringifiedMessageBody, iv).then(encryptedValue => { + delete message.body.identity.assertion; //TODO: Check why assertion is comming on the message! + delete message.body.identity.expires; //TODO: Check why expires is comming on the message! + let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); + + _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { + // log.log('hash ', hash); + + let newValue = {value: encode(encryptedValue), iv: encode(iv), hash: encode(hash)}; + + message.body.value = stringify(newValue); + resolve(message); + }); + }); + + // if not, just send the message + } else { + resolve(message); + } + + // start the generation of a new session Key + } else { + reject('Data object key could not be defined: Failed to decrypt message '); + } + }).catch(err => { reject('On encryptMessage from method dataObjectsStorage.getDataObject error: ' + err); }); + }).catch(err => { reject('On encryptMessage from method storageManager.get error: ' + err); }); + } + }); + } + +/* + encryptDataObject(dataObject, sender) { + let _this = this; + + return new Promise(function(resolve, reject) { + log.info('dataObject value to encrypt: ', dataObject); + + let dataObjectURL = parseMessageURL(sender); + + _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { + sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); + let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; + + //check if there is already a session key for the chat room + if (dataObjectKey) { + + // and if is to apply encryption, encrypt the messages + if (dataObjectKey.isToEncrypt) { + let iv = _this.crypto.generateIV(); + + _this.crypto.encryptAES(dataObjectKey.sessionKey, stringify(dataObject), iv).then(encryptedValue => { + let newValue = { value: encode(encryptedValue), iv: encode(iv) }; + + //log.log('encrypted dataObject', newValue); + return resolve(newValue); + }).catch(err => { reject('On encryptDataObject from method encryptAES error: ' + err); }); + + // if not, just send the message + } else { + log.info('The dataObject is not encrypted'); + return resolve(dataObject); + } + + // start the generation of a new session Key + } else { + return reject('No dataObjectKey for this dataObjectURL:', dataObjectURL); + } + }).catch(err => { reject('On encryptDataObject from method storageManager.get error: ' + err); }); + }); + } + + decryptMessage(message) { + let _this = this; + + // log.log('decryptMessage:message', message); + + return new Promise(function(resolve, reject) { + let isHandShakeType = message.type === 'handshake'; + + _this._isToDecrypt(message).then((isToDecrypt) => { + + //if is not to apply encryption, then returns resolve + if (!isToDecrypt) return resolve(message); + + let dataObjectURL = parseMessageURL(message.to); + + let isToDataObject = isDataObjectURL(dataObjectURL); + let isFromHyperty = divideURL(message.from).type === 'hyperty'; + let isToHyperty = divideURL(message.to).type === 'hyperty'; + + if (message.type === 'update') { + return resolve(message); + } + + //is is hyperty to hyperty communication + if (isFromHyperty && isToHyperty) { + // log.log('decrypt hyperty to hyperty'); + let userURL = _this.registry.getHypertyOwner(message.to); + if (userURL) { + + let chatKeys = _this.chatKeys[message.to + '<->' + message.from]; + if (!chatKeys) { + chatKeys = _this._newChatCrypto(message, userURL, 'decrypt'); + _this.chatKeys[message.to + '<->' + message.from] = chatKeys; + } + + if (chatKeys.authenticated && !isHandShakeType) { + let value = decode(message.body.value); + let iv = decodeToUint8Array(value.iv); + let data = decodeToUint8Array(value.value); + let hash = decodeToUint8Array(value.hash); + _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { + // log.log('decrypted value ', decryptedData); + message.body.value = decryptedData; + + let filteredMessage = filterMessageToHash(message, decryptedData + iv); + + _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { + log.log('Result of hash verification in decryptMessage: ', result); + message.body.assertedIdentity = true; + resolve(message); + }).chatch(err => { + console.log('decryptMessage HMAC failed:', err); + throw err; + }); + }); + + } else if (isHandShakeType) { + _this._doHandShakePhase(message, chatKeys).then(function(value) { + + //if it was started by doMutualAuthentication then ends the protocol + if (value === 'handShakeEnd') { + //reject('decrypt handshake protocol phase'); + + // if was started by a message, then resend that message + } else { + _this.chatKeys[message.to + '<->' + message.from] = value.chatKeys; + _this._messageBus.postMessage(value.message); + + //reject('decrypt handshake protocol phase '); + } + }); + } else { + reject('wrong message do decrypt'); + } + } else { + reject('error on decrypt message'); + } + + //if from hyperty to a dataObjectURL + } else if (isFromHyperty && isToDataObject) { + // log.log('dataObject value to decrypt: ', message.body); + + _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { + sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); + let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; + + if (dataObjectKey) { + + //check if is to apply encryption + if (dataObjectKey.isToEncrypt) { + let parsedValue = parse(message.body.value); + let iv = decodeToUint8Array(parsedValue.iv); + let encryptedValue = decodeToUint8Array(parsedValue.value); + let hash = decodeToUint8Array(parsedValue.hash); + + _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { + let parsedValue = parse(decryptedValue); + + // log.log('decrypted Value,', parsedValue); + message.body.value = parsedValue; + + let filteredMessage = filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); + + _this.crypto.verifyHMAC(dataObjectKey.sessionKey, filteredMessage, hash).then(result => { + log.log('Received message HMAC result', result); + + message.body.assertedIdentity = true; + resolve(message); + }).catch(err => { reject('Message HMAC is invalid: ' + err); }); + }); + + //if not, just return the message + } else { + message.body.assertedIdentity = true; + resolve(message); + } + + } else { + message.body.assertedIdentity = true; + resolve(message); + + //reject('no sessionKey for chat room found'); + } + }); + + } else { + reject('wrong message to decrypt'); + } + }); + + }); + } + + decryptDataObject(dataObject, sender) { + let _this = this; + + return new Promise(function(resolve, reject) { + //if is not to apply encryption, then returns resolve + if (!_this.isToUseEncryption) { + // log.log('decryption disabled'); + return resolve(dataObject); + } + + let dataObjectURL = parseMessageURL(sender); + + // log.log('dataObject value to decrypt: ', dataObject); + + _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { + sessionKeys = chatkeysToArrayCloner(sessionKeys); + let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; + + if (dataObjectKey) { + + //check if is to apply encryption + if (dataObjectKey.isToEncrypt) { + let iv = decodeToUint8Array(dataObject.iv); + let encryptedValue = decodeToUint8Array(dataObject.value); + + _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { + let parsedValue = parse(decryptedValue); + let newValue = { value: parsedValue, iv: encode(iv) }; + + // log.log('decrypted dataObject,', newValue); + + return resolve(newValue); + }).catch(err => { reject('On decryptDataObject from method encryptAES error: ' + err); }); + + //if not, just return the dataObject + } else { + // log.log('The dataObject is not encrypted'); + return resolve(dataObject); + } + + } else { + return reject('No dataObjectKey for this dataObjectURL:', dataObjectURL); + } + }); + }); + } + +*/ + + + /** +* generates the initial structure for the keys between two users +* @param {JSON} message initial message that triggers the mutual authentication +* @param {String} userURL userURL +* @param {boolean} receiver(Optional) indicates if is the sender or the receiver that creates a new chat crypto +* @return {JSON} newChatCrypto new JSON structure for the chat crypto +*/ + _newChatCrypto(message, userURL, receiver) { + let _this = this; + + //check whether is the sender or the receiver to create a new chatCrypto + //to mantain consistency on the keys if the receiver create a new chatCrypto, + //then invert the fields + let from = (receiver) ? message.to : message.from; + let to = (receiver) ? message.from : message.to; + + let userInfo = _this.idm.getIdentity(userURL); + + let newChatCrypto = + { + hypertyFrom: + { + hyperty: from, + userID: userInfo.userProfile.userURL, + + //privateKey: "getMyPublicKey", + //publicKey: "getMyPrivateKey", + assertion: userInfo.assertion, + messageInfo: userInfo + }, + hypertyTo: + { + hyperty: to, + userID: undefined, + publicKey: undefined, + assertion: undefined + }, + keys: + { + hypertyToSessionKey: undefined, + hypertyFromSessionKey: undefined, + hypertyToHashKey: undefined, + hypertyFromHashKey: undefined, + toRandom: undefined, + fromRandom: undefined, + premasterKey: undefined, + masterKey: undefined + }, + handshakeHistory: { + senderHello: undefined, + receiverHello: undefined, + senderCertificate: undefined, + receiverFinishedMessage: undefined + }, + initialMessage: (message.body.ignore) ? undefined : message, + callback: message.callback, + authenticated: false, + dataObjectURL: message.dataObjectURL + }; + + return newChatCrypto; + } +} + +/* +/** + * Identifies the messages to be encrypted + * @param {Message} message + * @returns {boolean} returns true if the message requires encryption + */ +/* +export function isToEncrypt(message) { + log.info('[CryptoManager.istoChyperModule]', message); + let isCreate = message.type === 'create'; + let isFromHyperty = message.from.includes('hyperty://'); + let isToHyperty = message.to.includes('hyperty://'); + let isToDataObject = isDataObjectURL(message.to); + + let doMutualAuthentication = message.body.hasOwnProperty('mutual') ? message.body.mutual : true; + + if (!doMutualAuthentication) return false; + + //if is not to apply encryption, then returns resolve + if (!this.isToUseEncryption && !(message.type === 'handshake')) { + log.info('not handshake: encryption disabled'); + return false; + } + + if (message.type === 'update') { + log.info('update:encryption disabled'); + return false; + } + + if (isLegacy(message.to)) return false; + + return ((isCreate && isFromHyperty && isToHyperty) || (isCreate && isFromHyperty && isToDataObject && doMutualAuthentication) || message.type === 'handshake' || (message.type === 'update' && doMutualAuthentication)); +} + +/* +export function isToDecrypt(message) { + let _this = this; + + return new Promise((resolve, reject) => { + // For sybscribe message let's start the mutualAuthentication + let isSubscription = message.type === 'subscribe'; + let isFromRemoteSM = _this._isFromRemoteSM(message.from); + + if (isSubscription & isFromRemoteSM) { + log.log('_doMutualAuthenticationPhase1'); + + _this._doMutualAuthenticationPhase1(message).then(() => { + resolve(false); + }, (error) => { + reject(error); + }); + + } else if (message.hasOwnProperty('body') && message.body.hasOwnProperty('value') && typeof message.body.value === 'string') { + log.log('_isToDecrypt:true'); + resolve(true); + } else { + log.log('_isToDecrypt:false'); + resolve(false); + } + + }).catch((error) => { + log.error('[CryptoManager._isToDecrypt]', error); + }); +} +*/ + +export default new MessageEncryptionHandling(); diff --git a/test/HypertyResourceStorage.spec.js b/test/HypertyResourceStorage.spec.js old mode 100644 new mode 100755 diff --git a/test/resources/generateData.js b/test/resources/generateData.js old mode 100644 new mode 100755 From 128bb33d07ab3b2c111a071d7ee11a1c1e8351f6 Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Fri, 26 Jan 2018 17:16:41 +0000 Subject: [PATCH 06/15] CryptoManager refactory 2 --- src/cryptoManager/CryptoManager.js | 9 ++- .../MessageEncryptionHandling.js | 81 ++++++++++--------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index 1b6ea96b..f8ddd6ee 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -5,7 +5,7 @@ import HandShakeProtocol from './HandShakeProtocol'; import {divideURL, isDataObjectURL, isLegacy, chatkeysToStringCloner, chatkeysToArrayCloner, parseMessageURL, parse, stringify, encode, decode, decodeToUint8Array, filterMessageToHash} from '../utils/utils.js'; -//import MessageEncryptionHandling from './MessageEncryptionHandling.js'; +import MessageEncryptionHandling from './MessageEncryptionHandling.js'; import Crypto from './Crypto'; @@ -31,6 +31,8 @@ class CryptoManager { init(runtimeURL, runtimeCapabilities, storageManager, dataObjectsStorage, registry, coreDiscovery, idm, runtimeFactory) { let _this = this; + console.log('xxx'); + if (!runtimeURL) throw new Error('[] runtimeURL is missing.'); if (!storageManager) throw new Error('storageManager is missing'); if (!runtimeFactory) throw new Error('runtimeFactory is missing'); @@ -59,7 +61,7 @@ class CryptoManager { _this._registry = registry; _this._coreDiscovery = coreDiscovery; - // _this._messageEncryptionHandling = new MessageEncryptionHandling(registry, _this.chatKeys, _this.crypto, this._idm); + _this._messageEncryptionHandling = new MessageEncryptionHandling(registry, _this.chatKeys, _this.crypto, this._idm); } //******************* GET AND SET METHODS ******************* @@ -209,7 +211,7 @@ class CryptoManager { if (isToLegacyIdentity) { resolve(message); } else if (isFromHyperty && isToHyperty) { - /* _this._messageEncryptionHandling.betweenHyperties(message).then(result => { + _this._messageEncryptionHandling.betweenHyperties(message).then(result => { if (result.isHandShakeNeeded) { resolve(result.message); } else { @@ -221,7 +223,6 @@ class CryptoManager { }); } }); -*/ //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { diff --git a/src/cryptoManager/MessageEncryptionHandling.js b/src/cryptoManager/MessageEncryptionHandling.js index f2b42a8e..2be1ba0b 100755 --- a/src/cryptoManager/MessageEncryptionHandling.js +++ b/src/cryptoManager/MessageEncryptionHandling.js @@ -13,7 +13,7 @@ class MessageEncryptionHandling { betweenHyperties(message) { let _this = this; - + console.log('xxx2'); return new Promise((resolve, reject) => { let userURL = _this.registry.getHypertyOwner(message.from); @@ -25,7 +25,7 @@ class MessageEncryptionHandling { if (!chatKeys) { chatKeys = _this._newChatCrypto(message, userURL); - //log.log('createChatKey encrypt', message.from + message.to); + //console.log('createChatKey encrypt', message.from + message.to); _this.chatKeys[message.from + '<->' + message.to] = chatKeys; message.body.handshakePhase = 'startHandShake'; } @@ -39,7 +39,7 @@ class MessageEncryptionHandling { stringify(iv), chatKeys.hypertyFrom.messageInfo); _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { - //log.log('result of hash ', hash); + //console.log('result of hash ', hash); let value = {iv: encode(iv), value: encode(encryptedValue), hash: encode(hash)}; message.body.value = encode(value); @@ -55,14 +55,15 @@ class MessageEncryptionHandling { } else { resolve({ message: message, isHandShakeNeeded: true}); - /* +/* _this._doHandShakePhase(message, chatKeys).then(function(value) { _this.chatKeys[message.from + '<->' + message.to] = value.chatKeys; _this._messageBus.postMessage(value.message); reject('encrypt handshake protocol phase '); + }); - */ +*/ } } else { reject('In encryptMessage: Hyperty owner URL was not found'); @@ -72,10 +73,10 @@ class MessageEncryptionHandling { /* encryptMessage(message) { - //log.info('encryptMessage:message', message); + //console.info('encryptMessage:message', message); let _this = this; - log.log('encrypt message '); + console.log('encrypt message '); return new Promise(function(resolve, reject) { @@ -83,7 +84,7 @@ class MessageEncryptionHandling { //if is not to apply encryption, then returns resolve if (!_this._isToEncrypt(message)) { - // log.log('decryption disabled'); + // console.log('decryption disabled'); return resolve(message); } @@ -95,7 +96,7 @@ class MessageEncryptionHandling { let isToHyperty = divideURL(message.to).type === 'hyperty'; if (message.type === 'update') { - log.log('encrypt message: message type update'); + console.log('encrypt message: message type update'); return resolve(message); } @@ -110,7 +111,7 @@ class MessageEncryptionHandling { if (!chatKeys) { chatKeys = _this._newChatCrypto(message, userURL); - //log.log('createChatKey encrypt', message.from + message.to); + //console.log('createChatKey encrypt', message.from + message.to); _this.chatKeys[message.from + '<->' + message.to] = chatKeys; message.body.handshakePhase = 'startHandShake'; } @@ -124,7 +125,7 @@ class MessageEncryptionHandling { stringify(iv), chatKeys.hypertyFrom.messageInfo); _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { - //log.log('result of hash ', hash); + //console.log('result of hash ', hash); let value = {iv: encode(iv), value: encode(encryptedValue), hash: encode(hash)}; message.body.value = encode(value); @@ -152,8 +153,8 @@ class MessageEncryptionHandling { //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { - //log.log('dataObject value to encrypt: ', message.body.value); - //log.log('IdentityModule - encrypt from hyperty to dataobject ', message); + //console.log('dataObject value to encrypt: ', message.body.value); + //console.log('IdentityModule - encrypt from hyperty to dataobject ', message); _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); @@ -192,7 +193,7 @@ class MessageEncryptionHandling { let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { - // log.log('hash ', hash); + // console.log('hash ', hash); let newValue = {value: encode(encryptedValue), iv: encode(iv), hash: encode(hash)}; @@ -221,7 +222,7 @@ class MessageEncryptionHandling { let _this = this; return new Promise(function(resolve, reject) { - log.info('dataObject value to encrypt: ', dataObject); + console.info('dataObject value to encrypt: ', dataObject); let dataObjectURL = parseMessageURL(sender); @@ -239,13 +240,13 @@ class MessageEncryptionHandling { _this.crypto.encryptAES(dataObjectKey.sessionKey, stringify(dataObject), iv).then(encryptedValue => { let newValue = { value: encode(encryptedValue), iv: encode(iv) }; - //log.log('encrypted dataObject', newValue); + //console.log('encrypted dataObject', newValue); return resolve(newValue); }).catch(err => { reject('On encryptDataObject from method encryptAES error: ' + err); }); // if not, just send the message } else { - log.info('The dataObject is not encrypted'); + console.info('The dataObject is not encrypted'); return resolve(dataObject); } @@ -260,7 +261,7 @@ class MessageEncryptionHandling { decryptMessage(message) { let _this = this; - // log.log('decryptMessage:message', message); + // console.log('decryptMessage:message', message); return new Promise(function(resolve, reject) { let isHandShakeType = message.type === 'handshake'; @@ -282,7 +283,7 @@ class MessageEncryptionHandling { //is is hyperty to hyperty communication if (isFromHyperty && isToHyperty) { - // log.log('decrypt hyperty to hyperty'); + // console.log('decrypt hyperty to hyperty'); let userURL = _this.registry.getHypertyOwner(message.to); if (userURL) { @@ -298,13 +299,13 @@ class MessageEncryptionHandling { let data = decodeToUint8Array(value.value); let hash = decodeToUint8Array(value.hash); _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { - // log.log('decrypted value ', decryptedData); + // console.log('decrypted value ', decryptedData); message.body.value = decryptedData; let filteredMessage = filterMessageToHash(message, decryptedData + iv); _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { - log.log('Result of hash verification in decryptMessage: ', result); + console.log('Result of hash verification in decryptMessage: ', result); message.body.assertedIdentity = true; resolve(message); }).chatch(err => { @@ -337,7 +338,7 @@ class MessageEncryptionHandling { //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { - // log.log('dataObject value to decrypt: ', message.body); + // console.log('dataObject value to decrypt: ', message.body); _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); @@ -355,13 +356,13 @@ class MessageEncryptionHandling { _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { let parsedValue = parse(decryptedValue); - // log.log('decrypted Value,', parsedValue); + // console.log('decrypted Value,', parsedValue); message.body.value = parsedValue; let filteredMessage = filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); _this.crypto.verifyHMAC(dataObjectKey.sessionKey, filteredMessage, hash).then(result => { - log.log('Received message HMAC result', result); + console.log('Received message HMAC result', result); message.body.assertedIdentity = true; resolve(message); @@ -396,13 +397,13 @@ class MessageEncryptionHandling { return new Promise(function(resolve, reject) { //if is not to apply encryption, then returns resolve if (!_this.isToUseEncryption) { - // log.log('decryption disabled'); + // console.log('decryption disabled'); return resolve(dataObject); } let dataObjectURL = parseMessageURL(sender); - // log.log('dataObject value to decrypt: ', dataObject); + // console.log('dataObject value to decrypt: ', dataObject); _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { sessionKeys = chatkeysToArrayCloner(sessionKeys); @@ -419,14 +420,14 @@ class MessageEncryptionHandling { let parsedValue = parse(decryptedValue); let newValue = { value: parsedValue, iv: encode(iv) }; - // log.log('decrypted dataObject,', newValue); + // console.log('decrypted dataObject,', newValue); return resolve(newValue); }).catch(err => { reject('On decryptDataObject from method encryptAES error: ' + err); }); //if not, just return the dataObject } else { - // log.log('The dataObject is not encrypted'); + // console.log('The dataObject is not encrypted'); return resolve(dataObject); } @@ -447,6 +448,7 @@ class MessageEncryptionHandling { * @param {boolean} receiver(Optional) indicates if is the sender or the receiver that creates a new chat crypto * @return {JSON} newChatCrypto new JSON structure for the chat crypto */ + _newChatCrypto(message, userURL, receiver) { let _this = this; @@ -504,15 +506,15 @@ class MessageEncryptionHandling { } } -/* + /** * Identifies the messages to be encrypted * @param {Message} message * @returns {boolean} returns true if the message requires encryption */ -/* + export function isToEncrypt(message) { - log.info('[CryptoManager.istoChyperModule]', message); + console.info('[CryptoManager.istoChyperModule]', message); let isCreate = message.type === 'create'; let isFromHyperty = message.from.includes('hyperty://'); let isToHyperty = message.to.includes('hyperty://'); @@ -524,12 +526,12 @@ export function isToEncrypt(message) { //if is not to apply encryption, then returns resolve if (!this.isToUseEncryption && !(message.type === 'handshake')) { - log.info('not handshake: encryption disabled'); + console.info('not handshake: encryption disabled'); return false; } if (message.type === 'update') { - log.info('update:encryption disabled'); + console.info('update:encryption disabled'); return false; } @@ -538,7 +540,7 @@ export function isToEncrypt(message) { return ((isCreate && isFromHyperty && isToHyperty) || (isCreate && isFromHyperty && isToDataObject && doMutualAuthentication) || message.type === 'handshake' || (message.type === 'update' && doMutualAuthentication)); } -/* + export function isToDecrypt(message) { let _this = this; @@ -548,7 +550,7 @@ export function isToDecrypt(message) { let isFromRemoteSM = _this._isFromRemoteSM(message.from); if (isSubscription & isFromRemoteSM) { - log.log('_doMutualAuthenticationPhase1'); + console.log('_doMutualAuthenticationPhase1'); _this._doMutualAuthenticationPhase1(message).then(() => { resolve(false); @@ -557,17 +559,16 @@ export function isToDecrypt(message) { }); } else if (message.hasOwnProperty('body') && message.body.hasOwnProperty('value') && typeof message.body.value === 'string') { - log.log('_isToDecrypt:true'); + console.log('_isToDecrypt:true'); resolve(true); } else { - log.log('_isToDecrypt:false'); + console.log('_isToDecrypt:false'); resolve(false); } }).catch((error) => { - log.error('[CryptoManager._isToDecrypt]', error); + console.error('[CryptoManager._isToDecrypt]', error); }); } -*/ -export default new MessageEncryptionHandling(); +module.exports = MessageEncryptionHandling; From 75bfbbdfd76e784836599933019394b689d24314 Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Fri, 26 Jan 2018 18:48:14 +0000 Subject: [PATCH 07/15] method betweenHyperties working --- src/cryptoManager/CryptoManager.js | 4 ++-- src/cryptoManager/MessageEncryptionHandling.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index f8ddd6ee..644d1ccd 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -212,10 +212,10 @@ class CryptoManager { resolve(message); } else if (isFromHyperty && isToHyperty) { _this._messageEncryptionHandling.betweenHyperties(message).then(result => { - if (result.isHandShakeNeeded) { + if (!result.isHandShakeNeeded) { resolve(result.message); } else { - _this._doHandShakePhase(result.message, _this.chatKeys).then(function(value) { + _this._doHandShakePhase(result.message, result.chatKeys).then(function(value) { _this.chatKeys[message.from + '<->' + message.to] = value.chatKeys; _this._messageBus.postMessage(value.message); diff --git a/src/cryptoManager/MessageEncryptionHandling.js b/src/cryptoManager/MessageEncryptionHandling.js index 2be1ba0b..b50f6fdd 100755 --- a/src/cryptoManager/MessageEncryptionHandling.js +++ b/src/cryptoManager/MessageEncryptionHandling.js @@ -53,7 +53,7 @@ class MessageEncryptionHandling { // else, starts a new handshake protocol } else { - resolve({ message: message, isHandShakeNeeded: true}); + resolve({ message: message, isHandShakeNeeded: true, chatKeys: chatKeys}); /* _this._doHandShakePhase(message, chatKeys).then(function(value) { From 938a98aebc7e62e643278a336f817273f89d5d7f Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Mon, 29 Jan 2018 16:30:37 +0000 Subject: [PATCH 08/15] Added encryptBetweenHypertyDataObject --- src/cryptoManager/CryptoManager.js | 70 ++------------ .../MessageEncryptionHandling.js | 93 ++++++++++++++++--- 2 files changed, 91 insertions(+), 72 deletions(-) diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index 644d1ccd..f0b7dbcb 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -61,7 +61,9 @@ class CryptoManager { _this._registry = registry; _this._coreDiscovery = coreDiscovery; - _this._messageEncryptionHandling = new MessageEncryptionHandling(registry, _this.chatKeys, _this.crypto, this._idm); + _this._messageEncryptionHandling = new + MessageEncryptionHandling(_this._registry, _this.chatKeys, _this.crypto, + _this._idm, _this.storageManager, _this.dataObjectsStorage); } //******************* GET AND SET METHODS ******************* @@ -196,7 +198,6 @@ class CryptoManager { } let dataObjectURL = parseMessageURL(message.to); - let isToDataObject = isDataObjectURL(dataObjectURL); let isToLegacyIdentity = isLegacy(message.to); let isFromHyperty = divideURL(message.from).type === 'hyperty'; @@ -210,8 +211,9 @@ class CryptoManager { //------------> Needs tests! if (isToLegacyIdentity) { resolve(message); + } else if (isFromHyperty && isToHyperty) { - _this._messageEncryptionHandling.betweenHyperties(message).then(result => { + _this._messageEncryptionHandling.encryptBetweenHyperties(message).then(result => { if (!result.isHandShakeNeeded) { resolve(result.message); } else { @@ -223,73 +225,21 @@ class CryptoManager { }); } }); + //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { //log.log('dataObject value to encrypt: ', message.body.value); //log.log('IdentityModule - encrypt from hyperty to dataobject ', message); - _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { - sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); - let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; - - _this.dataObjectsStorage.getDataObject(dataObjectURL).then((isHypertyReporter) => { - //if no key exists, create a new one if is the reporter of dataObject - if (!dataObjectKey) { - // if the hyperty is the reporter of the dataObject then generates a session key - if (isHypertyReporter.reporter && isHypertyReporter.reporter === message.from) { - - let sessionKey = _this.crypto.generateRandom(); - _this.dataObjectSessionKeys[dataObjectURL] = {sessionKey: sessionKey, isToEncrypt: true}; - let dataObjectSessionKeysClone = chatkeysToStringCloner(_this.dataObjectSessionKeys); - - //TODO: check if this does not need to be stored - _this.storageManager.set('dataObjectSessionKeys', 0, dataObjectSessionKeysClone).catch(err => { - reject('On encryptMessage from method storageManager.set error: ' + err); - }); - dataObjectKey = _this.dataObjectSessionKeys[dataObjectURL]; - } - } - - //check if there is already a session key for the chat room - if (dataObjectKey) { - - // and if is to apply encryption, encrypt the messages - if (dataObjectKey.isToEncrypt) { - let iv = _this.crypto.generateIV(); - let stringifiedIV = stringify(iv); - let stringifiedMessageBody = stringify(message.body.value); - - _this.crypto.encryptAES(dataObjectKey.sessionKey, stringifiedMessageBody, iv).then(encryptedValue => { - delete message.body.identity.assertion; //TODO: Check why assertion is comming on the message! - delete message.body.identity.expires; //TODO: Check why expires is comming on the message! - let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); - - _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { - // log.log('hash ', hash); - - let newValue = {value: encode(encryptedValue), iv: encode(iv), hash: encode(hash)}; - - message.body.value = stringify(newValue); - resolve(message); - }); - }); - - // if not, just send the message - } else { - resolve(message); - } - - // start the generation of a new session Key - } else { - reject('Data object key could not be defined: Failed to decrypt message '); - } - }).catch(err => { reject('On encryptMessage from method dataObjectsStorage.getDataObject error: ' + err); }); - }).catch(err => { reject('On encryptMessage from method storageManager.get error: ' + err); }); + _this._messageEncryptionHandling.encryptoBetweenHypertyDataObject(message).then(result =>{ + resolve(result) + }).catch(err => { reject('On encryptMessage from method _messageEncryptionHandling error: ' + err); }); } }); } + encryptDataObject(dataObject, sender) { let _this = this; diff --git a/src/cryptoManager/MessageEncryptionHandling.js b/src/cryptoManager/MessageEncryptionHandling.js index b50f6fdd..73363733 100755 --- a/src/cryptoManager/MessageEncryptionHandling.js +++ b/src/cryptoManager/MessageEncryptionHandling.js @@ -4,14 +4,16 @@ import {divideURL, isDataObjectURL, isLegacy, chatkeysToStringCloner, chatkeysTo class MessageEncryptionHandling { - constructor(registry, chatKeys, crypto, idm) { + constructor(registry, chatKeys, crypto, idm, storageManager, dataObjectsStorage) { this.registry = registry; this.chatKeys = chatKeys; this.crypto = crypto; this.idm = idm; + this.storageManager = storageManager; + this.dataObjectsStorage = dataObjectsStorage; } - betweenHyperties(message) { + encryptBetweenHyperties(message) { let _this = this; console.log('xxx2'); return new Promise((resolve, reject) => { @@ -54,16 +56,6 @@ class MessageEncryptionHandling { // else, starts a new handshake protocol } else { resolve({ message: message, isHandShakeNeeded: true, chatKeys: chatKeys}); - -/* - _this._doHandShakePhase(message, chatKeys).then(function(value) { - _this.chatKeys[message.from + '<->' + message.to] = value.chatKeys; - - _this._messageBus.postMessage(value.message); - reject('encrypt handshake protocol phase '); - - }); -*/ } } else { reject('In encryptMessage: Hyperty owner URL was not found'); @@ -71,6 +63,83 @@ class MessageEncryptionHandling { }); } + + + + + encryptBetweenHypertyDataObject(message) { + let _this = this; + return new Promise((resolve, reject) => { + let dataObjectURL = parseMessageURL(message.to); + _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { + sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); + let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; + + _this.dataObjectsStorage.getDataObject(dataObjectURL).then((isHypertyReporter) => { + //if no key exists, create a new one if is the reporter of dataObject + if (!dataObjectKey) { + // if the hyperty is the reporter of the dataObject then generates a session key + if (isHypertyReporter.reporter && isHypertyReporter.reporter === message.from) { + + let sessionKey = _this.crypto.generateRandom(); + _this.dataObjectSessionKeys[dataObjectURL] = {sessionKey: sessionKey, isToEncrypt: true}; + let dataObjectSessionKeysClone = chatkeysToStringCloner(_this.dataObjectSessionKeys); + + //TODO: check if this does not need to be stored + _this.storageManager.set('dataObjectSessionKeys', 0, dataObjectSessionKeysClone).catch(err => { + reject('On encryptMessage from method storageManager.set error: ' + err); + }); + dataObjectKey = _this.dataObjectSessionKeys[dataObjectURL]; + } + } + + //check if there is already a session key for the chat room + if (dataObjectKey) { + + // and if is to apply encryption, encrypt the messages + if (dataObjectKey.isToEncrypt) { + let iv = _this.crypto.generateIV(); + let stringifiedIV = stringify(iv); + let stringifiedMessageBody = stringify(message.body.value); + + _this.crypto.encryptAES(dataObjectKey.sessionKey, stringifiedMessageBody, iv).then(encryptedValue => { + delete message.body.identity.assertion; //TODO: Check why assertion is comming on the message! + delete message.body.identity.expires; //TODO: Check why expires is comming on the message! + let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); + + _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { + // log.log('hash ', hash); + + let newValue = {value: encode(encryptedValue), iv: encode(iv), hash: encode(hash)}; + + message.body.value = stringify(newValue); + resolve(message); + }); + }); + + // if not, just send the message + } else { + resolve(message); + } + + // start the generation of a new session Key + } else { + reject('Data object key could not be defined: Failed to decrypt message '); + } + }).catch(err => { reject('On encryptMessage from method dataObjectsStorage.getDataObject error: ' + err); }); + }).catch(err => { reject('On encryptMessage from method storageManager.get error: ' + err); }); + + + + }); + } + + + + + + + /* encryptMessage(message) { //console.info('encryptMessage:message', message); From cdbf60b12251a5ae240ad71bc27b64614f5a73ab Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Mon, 29 Jan 2018 18:57:03 +0000 Subject: [PATCH 09/15] Added decryptBetweenHypertyDataObject and decryptBetweenHyperties --- src/cryptoManager/CryptoManager.js | 102 +---- .../MessageEncryptionHandling.js | 403 +++--------------- 2 files changed, 72 insertions(+), 433 deletions(-) diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index f0b7dbcb..aa5580bc 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -193,7 +193,6 @@ class CryptoManager { //if is not to apply encryption, then returns resolve if (!_this._isToEncrypt(message)) { - // log.log('decryption disabled'); return resolve(message); } @@ -228,11 +227,7 @@ class CryptoManager { //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { - - //log.log('dataObject value to encrypt: ', message.body.value); - //log.log('IdentityModule - encrypt from hyperty to dataobject ', message); - - _this._messageEncryptionHandling.encryptoBetweenHypertyDataObject(message).then(result =>{ + _this._messageEncryptionHandling.encryptBetweenHypertyDataObject(message).then(result =>{ resolve(result) }).catch(err => { reject('On encryptMessage from method _messageEncryptionHandling error: ' + err); }); } @@ -305,40 +300,12 @@ class CryptoManager { //is is hyperty to hyperty communication if (isFromHyperty && isToHyperty) { - // log.log('decrypt hyperty to hyperty'); - let userURL = _this._registry.getHypertyOwner(message.to); - if (userURL) { - - let chatKeys = _this.chatKeys[message.to + '<->' + message.from]; - if (!chatKeys) { - chatKeys = _this._newChatCrypto(message, userURL, 'decrypt'); - _this.chatKeys[message.to + '<->' + message.from] = chatKeys; - } - - if (chatKeys.authenticated && !isHandShakeType) { - let value = decode(message.body.value); - let iv = decodeToUint8Array(value.iv); - let data = decodeToUint8Array(value.value); - let hash = decodeToUint8Array(value.hash); - _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { - // log.log('decrypted value ', decryptedData); - message.body.value = decryptedData; - - let filteredMessage = filterMessageToHash(message, decryptedData + iv); - - _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { - log.log('Result of hash verification in decryptMessage: ', result); - message.body.assertedIdentity = true; - resolve(message); - }).chatch(err => { - console.log('decryptMessage HMAC failed:', err); - throw err; - }); - }); - - } else if (isHandShakeType) { - _this._doHandShakePhase(message, chatKeys).then(function(value) { + _this._messageEncryptionHandling.decryptBetweenHyperties(message).then(result => { + if (!result.isHandShakeNeeded) { + resolve(result.message); + } else { + _this._doHandShakePhase(result.message, result.chatKeys).then(function(value) { //if it was started by doMutualAuthentication then ends the protocol if (value === 'handShakeEnd') { //reject('decrypt handshake protocol phase'); @@ -348,63 +315,18 @@ class CryptoManager { _this.chatKeys[message.to + '<->' + message.from] = value.chatKeys; _this._messageBus.postMessage(value.message); - //reject('decrypt handshake protocol phase '); + //reject('decrypt handshake protocol phase '); TODO: Check why is this commented? } - }); - } else { - reject('wrong message do decrypt'); + }).catch(err => { reject('Error on decrypting message handshake in decryptBetweenHyperties: ', err); }); } - } else { - reject('error on decrypt message'); - } + }).catch(err => { reject('Error on decrypting message in decryptBetweenHyperties: ', err); }); //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { // log.log('dataObject value to decrypt: ', message.body); - - _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { - sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); - let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; - - if (dataObjectKey) { - - //check if is to apply encryption - if (dataObjectKey.isToEncrypt) { - let parsedValue = parse(message.body.value); - let iv = decodeToUint8Array(parsedValue.iv); - let encryptedValue = decodeToUint8Array(parsedValue.value); - let hash = decodeToUint8Array(parsedValue.hash); - - _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { - let parsedValue = parse(decryptedValue); - - // log.log('decrypted Value,', parsedValue); - message.body.value = parsedValue; - - let filteredMessage = filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); - - _this.crypto.verifyHMAC(dataObjectKey.sessionKey, filteredMessage, hash).then(result => { - log.log('Received message HMAC result', result); - - message.body.assertedIdentity = true; - resolve(message); - }).catch(err => { reject('Message HMAC is invalid: ' + err); }); - }); - - //if not, just return the message - } else { - message.body.assertedIdentity = true; - resolve(message); - } - - } else { - message.body.assertedIdentity = true; - resolve(message); - - //reject('no sessionKey for chat room found'); - } - }); - + _this._messageEncryptionHandling.decryptBetweenHypertyDataObject(message).then(result => { + resolve(result); + }).catch(err => { reject('Error on decrypting message in decryptBetweenHyperties: ', err); }); } else { reject('wrong message to decrypt'); } diff --git a/src/cryptoManager/MessageEncryptionHandling.js b/src/cryptoManager/MessageEncryptionHandling.js index 73363733..6d1c90ff 100755 --- a/src/cryptoManager/MessageEncryptionHandling.js +++ b/src/cryptoManager/MessageEncryptionHandling.js @@ -64,9 +64,6 @@ class MessageEncryptionHandling { } - - - encryptBetweenHypertyDataObject(message) { let _this = this; return new Promise((resolve, reject) => { @@ -108,7 +105,7 @@ class MessageEncryptionHandling { let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { - // log.log('hash ', hash); + // console.log('hash ', hash); let newValue = {value: encode(encryptedValue), iv: encode(iv), hash: encode(hash)}; @@ -124,390 +121,110 @@ class MessageEncryptionHandling { // start the generation of a new session Key } else { - reject('Data object key could not be defined: Failed to decrypt message '); + reject('Data object key could not be defined: Failed to encrypt message '); } }).catch(err => { reject('On encryptMessage from method dataObjectsStorage.getDataObject error: ' + err); }); }).catch(err => { reject('On encryptMessage from method storageManager.get error: ' + err); }); - - }); } - - - - - - /* - encryptMessage(message) { - //console.info('encryptMessage:message', message); + decryptBetweenHyperties(message) { let _this = this; - - console.log('encrypt message '); - - return new Promise(function(resolve, reject) { - + return new Promise((resolve, reject) => { let isHandShakeType = message.type === 'handshake'; + let userURL = _this.registry.getHypertyOwner(message.to); + if (userURL) { - //if is not to apply encryption, then returns resolve - if (!_this._isToEncrypt(message)) { - // console.log('decryption disabled'); - return resolve(message); - } - - let dataObjectURL = parseMessageURL(message.to); - - let isToDataObject = isDataObjectURL(dataObjectURL); - let isToLegacyIdentity = isLegacy(message.to); - let isFromHyperty = divideURL(message.from).type === 'hyperty'; - let isToHyperty = divideURL(message.to).type === 'hyperty'; - - if (message.type === 'update') { - console.log('encrypt message: message type update'); - return resolve(message); - } - - if (isToLegacyIdentity) { - resolve(message); - } else if (isFromHyperty && isToHyperty) { - let userURL = _this.registry.getHypertyOwner(message.from); - if (userURL) { - - // check if exists any keys between two users - let chatKeys = _this.chatKeys[message.from + '<->' + message.to]; - if (!chatKeys) { - chatKeys = _this._newChatCrypto(message, userURL); - - //console.log('createChatKey encrypt', message.from + message.to); - _this.chatKeys[message.from + '<->' + message.to] = chatKeys; - message.body.handshakePhase = 'startHandShake'; - } - - if (chatKeys.authenticated && !isHandShakeType) { - - let iv = _this.crypto.generateIV(); - _this.crypto.encryptAES(chatKeys.keys.hypertyFromSessionKey, stringify(message.body.value), iv).then(encryptedValue => { - - let filteredMessage = filterMessageToHash(message, stringify(message.body.value) + - stringify(iv), chatKeys.hypertyFrom.messageInfo); - - _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { - //console.log('result of hash ', hash); - let value = {iv: encode(iv), value: encode(encryptedValue), hash: encode(hash)}; - message.body.value = encode(value); + let chatKeys = _this.chatKeys[message.to + '<->' + message.from]; + if (!chatKeys) { + chatKeys = _this._newChatCrypto(message, userURL, 'decrypt'); + _this.chatKeys[message.to + '<->' + message.from] = chatKeys; + } - resolve(message); - }); + if (chatKeys.authenticated && !isHandShakeType) { + let value = decode(message.body.value); + let iv = decodeToUint8Array(value.iv); + let data = decodeToUint8Array(value.value); + let hash = decodeToUint8Array(value.hash); + _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { + // console.log('decrypted value ', decryptedData); + message.body.value = decryptedData; + + let filteredMessage = filterMessageToHash(message, decryptedData + iv); + + _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { + console.log('Result of hash verification in decryptMessage: ', result); + message.body.assertedIdentity = true; + resolve({message: message, isHandShakeNeeded: false}); + }).chatch(err => { + console.log('decryptMessage HMAC failed:', err); + throw err; }); + }); - // if is a handshake message, just resolve it - } else if (isHandShakeType) { - resolve(message); - - // else, starts a new handshake protocol - } else { - _this._doHandShakePhase(message, chatKeys).then(function(value) { - _this.chatKeys[message.from + '<->' + message.to] = value.chatKeys; - - _this._messageBus.postMessage(value.message); - reject('encrypt handshake protocol phase '); - }); - } + } else if (isHandShakeType) { + resolve({ message: message, chatKeys: chatKeys, isHandShakeNeeded: true}); } else { - reject('In encryptMessage: Hyperty owner URL was not found'); + reject('Wrong message do decrypt: '); } - - //if from hyperty to a dataObjectURL - } else if (isFromHyperty && isToDataObject) { - - //console.log('dataObject value to encrypt: ', message.body.value); - //console.log('IdentityModule - encrypt from hyperty to dataobject ', message); - - _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { - sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); - let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; - - _this.dataObjectsStorage.getDataObject(dataObjectURL).then((isHypertyReporter) => { - //if no key exists, create a new one if is the reporter of dataObject - if (!dataObjectKey) { - // if the hyperty is the reporter of the dataObject then generates a session key - if (isHypertyReporter.reporter && isHypertyReporter.reporter === message.from) { - - let sessionKey = _this.crypto.generateRandom(); - _this.dataObjectSessionKeys[dataObjectURL] = {sessionKey: sessionKey, isToEncrypt: true}; - let dataObjectSessionKeysClone = chatkeysToStringCloner(_this.dataObjectSessionKeys); - - //TODO: check if this does not need to be stored - _this.storageManager.set('dataObjectSessionKeys', 0, dataObjectSessionKeysClone).catch(err => { - reject('On encryptMessage from method storageManager.set error: ' + err); - }); - dataObjectKey = _this.dataObjectSessionKeys[dataObjectURL]; - } - } - - //check if there is already a session key for the chat room - if (dataObjectKey) { - - // and if is to apply encryption, encrypt the messages - if (dataObjectKey.isToEncrypt) { - let iv = _this.crypto.generateIV(); - let stringifiedIV = stringify(iv); - let stringifiedMessageBody = stringify(message.body.value); - - _this.crypto.encryptAES(dataObjectKey.sessionKey, stringifiedMessageBody, iv).then(encryptedValue => { - delete message.body.identity.assertion; //TODO: Check why assertion is comming on the message! - delete message.body.identity.expires; //TODO: Check why expires is comming on the message! - let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); - - _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { - // console.log('hash ', hash); - - let newValue = {value: encode(encryptedValue), iv: encode(iv), hash: encode(hash)}; - - message.body.value = stringify(newValue); - resolve(message); - }); - }); - - // if not, just send the message - } else { - resolve(message); - } - - // start the generation of a new session Key - } else { - reject('Data object key could not be defined: Failed to decrypt message '); - } - }).catch(err => { reject('On encryptMessage from method dataObjectsStorage.getDataObject error: ' + err); }); - }).catch(err => { reject('On encryptMessage from method storageManager.get error: ' + err); }); + } else { + reject('Error on decrypt message:'); } }); } -/* - encryptDataObject(dataObject, sender) { - let _this = this; - - return new Promise(function(resolve, reject) { - console.info('dataObject value to encrypt: ', dataObject); - - let dataObjectURL = parseMessageURL(sender); + decryptBetweenHypertyDataObject(message) { + let _this = this; + return new Promise((resolve, reject) => { + let dataObjectURL = parseMessageURL(message.to); _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; - //check if there is already a session key for the chat room if (dataObjectKey) { - // and if is to apply encryption, encrypt the messages + //check if is to apply encryption if (dataObjectKey.isToEncrypt) { - let iv = _this.crypto.generateIV(); - - _this.crypto.encryptAES(dataObjectKey.sessionKey, stringify(dataObject), iv).then(encryptedValue => { - let newValue = { value: encode(encryptedValue), iv: encode(iv) }; + let parsedValue = parse(message.body.value); + let iv = decodeToUint8Array(parsedValue.iv); + let encryptedValue = decodeToUint8Array(parsedValue.value); + let hash = decodeToUint8Array(parsedValue.hash); - //console.log('encrypted dataObject', newValue); - return resolve(newValue); - }).catch(err => { reject('On encryptDataObject from method encryptAES error: ' + err); }); - - // if not, just send the message - } else { - console.info('The dataObject is not encrypted'); - return resolve(dataObject); - } - - // start the generation of a new session Key - } else { - return reject('No dataObjectKey for this dataObjectURL:', dataObjectURL); - } - }).catch(err => { reject('On encryptDataObject from method storageManager.get error: ' + err); }); - }); - } - - decryptMessage(message) { - let _this = this; - - // console.log('decryptMessage:message', message); - - return new Promise(function(resolve, reject) { - let isHandShakeType = message.type === 'handshake'; - - _this._isToDecrypt(message).then((isToDecrypt) => { - - //if is not to apply encryption, then returns resolve - if (!isToDecrypt) return resolve(message); - - let dataObjectURL = parseMessageURL(message.to); - - let isToDataObject = isDataObjectURL(dataObjectURL); - let isFromHyperty = divideURL(message.from).type === 'hyperty'; - let isToHyperty = divideURL(message.to).type === 'hyperty'; - - if (message.type === 'update') { - return resolve(message); - } - - //is is hyperty to hyperty communication - if (isFromHyperty && isToHyperty) { - // console.log('decrypt hyperty to hyperty'); - let userURL = _this.registry.getHypertyOwner(message.to); - if (userURL) { - - let chatKeys = _this.chatKeys[message.to + '<->' + message.from]; - if (!chatKeys) { - chatKeys = _this._newChatCrypto(message, userURL, 'decrypt'); - _this.chatKeys[message.to + '<->' + message.from] = chatKeys; - } - - if (chatKeys.authenticated && !isHandShakeType) { - let value = decode(message.body.value); - let iv = decodeToUint8Array(value.iv); - let data = decodeToUint8Array(value.value); - let hash = decodeToUint8Array(value.hash); - _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { - // console.log('decrypted value ', decryptedData); - message.body.value = decryptedData; - - let filteredMessage = filterMessageToHash(message, decryptedData + iv); - - _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { - console.log('Result of hash verification in decryptMessage: ', result); - message.body.assertedIdentity = true; - resolve(message); - }).chatch(err => { - console.log('decryptMessage HMAC failed:', err); - throw err; - }); - }); - - } else if (isHandShakeType) { - _this._doHandShakePhase(message, chatKeys).then(function(value) { - - //if it was started by doMutualAuthentication then ends the protocol - if (value === 'handShakeEnd') { - //reject('decrypt handshake protocol phase'); - - // if was started by a message, then resend that message - } else { - _this.chatKeys[message.to + '<->' + message.from] = value.chatKeys; - _this._messageBus.postMessage(value.message); - - //reject('decrypt handshake protocol phase '); - } - }); - } else { - reject('wrong message do decrypt'); - } - } else { - reject('error on decrypt message'); - } - - //if from hyperty to a dataObjectURL - } else if (isFromHyperty && isToDataObject) { - // console.log('dataObject value to decrypt: ', message.body); - - _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { - sessionKeys = chatkeysToArrayCloner(sessionKeys || {}); - let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; - - if (dataObjectKey) { - - //check if is to apply encryption - if (dataObjectKey.isToEncrypt) { - let parsedValue = parse(message.body.value); - let iv = decodeToUint8Array(parsedValue.iv); - let encryptedValue = decodeToUint8Array(parsedValue.value); - let hash = decodeToUint8Array(parsedValue.hash); - - _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { - let parsedValue = parse(decryptedValue); + _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { + let parsedValue = parse(decryptedValue); - // console.log('decrypted Value,', parsedValue); - message.body.value = parsedValue; + // console.log('decrypted Value,', parsedValue); + message.body.value = parsedValue; - let filteredMessage = filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); + let filteredMessage = filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); - _this.crypto.verifyHMAC(dataObjectKey.sessionKey, filteredMessage, hash).then(result => { - console.log('Received message HMAC result', result); + _this.crypto.verifyHMAC(dataObjectKey.sessionKey, filteredMessage, hash).then(result => { + console.log('Received message HMAC result', result); - message.body.assertedIdentity = true; - resolve(message); - }).catch(err => { reject('Message HMAC is invalid: ' + err); }); - }); - - //if not, just return the message - } else { message.body.assertedIdentity = true; resolve(message); - } - - } else { - message.body.assertedIdentity = true; - resolve(message); - - //reject('no sessionKey for chat room found'); - } - }); - - } else { - reject('wrong message to decrypt'); - } - }); - - }); - } - - decryptDataObject(dataObject, sender) { - let _this = this; - - return new Promise(function(resolve, reject) { - //if is not to apply encryption, then returns resolve - if (!_this.isToUseEncryption) { - // console.log('decryption disabled'); - return resolve(dataObject); - } - - let dataObjectURL = parseMessageURL(sender); - - // console.log('dataObject value to decrypt: ', dataObject); - - _this.storageManager.get('dataObjectSessionKeys').then((sessionKeys) => { - sessionKeys = chatkeysToArrayCloner(sessionKeys); - let dataObjectKey = sessionKeys ? sessionKeys[dataObjectURL] : null; - - if (dataObjectKey) { - - //check if is to apply encryption - if (dataObjectKey.isToEncrypt) { - let iv = decodeToUint8Array(dataObject.iv); - let encryptedValue = decodeToUint8Array(dataObject.value); - - _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { - let parsedValue = parse(decryptedValue); - let newValue = { value: parsedValue, iv: encode(iv) }; - - // console.log('decrypted dataObject,', newValue); - - return resolve(newValue); - }).catch(err => { reject('On decryptDataObject from method encryptAES error: ' + err); }); + }).catch(err => { reject('Message HMAC is invalid: ' + err); }); + }); - //if not, just return the dataObject + //if not, just return the message } else { - // console.log('The dataObject is not encrypted'); - return resolve(dataObject); + message.body.assertedIdentity = true; + resolve(message); } } else { - return reject('No dataObjectKey for this dataObjectURL:', dataObjectURL); + message.body.assertedIdentity = true; + resolve(message); + + //reject('no sessionKey for chat room found'); } }); }); } -*/ /** From 9f81c4f2f6694414c645b424dba023ae3cd995a7 Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Thu, 1 Feb 2018 15:47:31 +0000 Subject: [PATCH 10/15] Finished refactory --- src/cryptoManager/CryptoManager.js | 71 ++--------- .../MessageEncryptionHandling.js | 111 ++++-------------- 2 files changed, 30 insertions(+), 152 deletions(-) diff --git a/src/cryptoManager/CryptoManager.js b/src/cryptoManager/CryptoManager.js index aa5580bc..08938d55 100755 --- a/src/cryptoManager/CryptoManager.js +++ b/src/cryptoManager/CryptoManager.js @@ -4,7 +4,7 @@ let log = logger.getLogger('CryptoManager'); import HandShakeProtocol from './HandShakeProtocol'; import {divideURL, isDataObjectURL, isLegacy, chatkeysToStringCloner, chatkeysToArrayCloner, parseMessageURL, - parse, stringify, encode, decode, decodeToUint8Array, filterMessageToHash} from '../utils/utils.js'; + parse, stringify, encode, decodeToUint8Array, filterMessageToHash} from '../utils/utils.js'; import MessageEncryptionHandling from './MessageEncryptionHandling.js'; import Crypto from './Crypto'; @@ -31,8 +31,6 @@ class CryptoManager { init(runtimeURL, runtimeCapabilities, storageManager, dataObjectsStorage, registry, coreDiscovery, idm, runtimeFactory) { let _this = this; - console.log('xxx'); - if (!runtimeURL) throw new Error('[] runtimeURL is missing.'); if (!storageManager) throw new Error('storageManager is missing'); if (!runtimeFactory) throw new Error('runtimeFactory is missing'); @@ -61,9 +59,8 @@ class CryptoManager { _this._registry = registry; _this._coreDiscovery = coreDiscovery; - _this._messageEncryptionHandling = new - MessageEncryptionHandling(_this._registry, _this.chatKeys, _this.crypto, - _this._idm, _this.storageManager, _this.dataObjectsStorage); + _this._messageEncryptionHandling = new MessageEncryptionHandling(_this._registry, + _this.chatKeys, _this.crypto, _this.storageManager, _this.dataObjectsStorage); } //******************* GET AND SET METHODS ******************* @@ -228,7 +225,7 @@ class CryptoManager { //if from hyperty to a dataObjectURL } else if (isFromHyperty && isToDataObject) { _this._messageEncryptionHandling.encryptBetweenHypertyDataObject(message).then(result =>{ - resolve(result) + resolve(result); }).catch(err => { reject('On encryptMessage from method _messageEncryptionHandling error: ' + err); }); } }); @@ -281,8 +278,6 @@ class CryptoManager { // log.log('decryptMessage:message', message); return new Promise(function(resolve, reject) { - let isHandShakeType = message.type === 'handshake'; - _this._isToDecrypt(message).then((isToDecrypt) => { //if is not to apply encryption, then returns resolve @@ -605,7 +600,7 @@ class CryptoManager { let handshakeType = message.body.handshakePhase; - console.info('handshake phase: ', handshakeType); + log.info('handshake phase: ', handshakeType); switch (handshakeType) { @@ -676,61 +671,11 @@ class CryptoManager { * @return {JSON} newChatCrypto new JSON structure for the chat crypto */ _newChatCrypto(message, userURL, receiver) { - let _this = this; - - //check whether is the sender or the receiver to create a new chatCrypto - //to mantain consistency on the keys if the receiver create a new chatCrypto, - //then invert the fields - let from = (receiver) ? message.to : message.from; - let to = (receiver) ? message.from : message.to; - - let userInfo = _this._idm.getIdentity(userURL); - - let newChatCrypto = - { - hypertyFrom: - { - hyperty: from, - userID: userInfo.userProfile.userURL, - - //privateKey: "getMyPublicKey", - //publicKey: "getMyPrivateKey", - assertion: userInfo.assertion, - messageInfo: userInfo - }, - hypertyTo: - { - hyperty: to, - userID: undefined, - publicKey: undefined, - assertion: undefined - }, - keys: - { - hypertyToSessionKey: undefined, - hypertyFromSessionKey: undefined, - hypertyToHashKey: undefined, - hypertyFromHashKey: undefined, - toRandom: undefined, - fromRandom: undefined, - premasterKey: undefined, - masterKey: undefined - }, - handshakeHistory: { - senderHello: undefined, - receiverHello: undefined, - senderCertificate: undefined, - receiverFinishedMessage: undefined - }, - initialMessage: (message.body.ignore) ? undefined : message, - callback: message.callback, - authenticated: false, - dataObjectURL: message.dataObjectURL - }; - - return newChatCrypto; + let userInfo = this._idm.getIdentity(userURL); + return this._messageEncryptionHandling.newChatCrypto(message, userURL, receiver, userInfo); } + /** * Retrieves a public keys given a user refrence. If no key is found, generates a new key asymmetric key and retrieves the public keys. diff --git a/src/cryptoManager/MessageEncryptionHandling.js b/src/cryptoManager/MessageEncryptionHandling.js index 6d1c90ff..85e57a0d 100755 --- a/src/cryptoManager/MessageEncryptionHandling.js +++ b/src/cryptoManager/MessageEncryptionHandling.js @@ -1,21 +1,28 @@ -import {divideURL, isDataObjectURL, isLegacy, chatkeysToStringCloner, chatkeysToArrayCloner, parseMessageURL, +import {chatkeysToStringCloner, chatkeysToArrayCloner, parseMessageURL, parse, stringify, encode, decode, decodeToUint8Array, filterMessageToHash} from '../utils/utils.js'; +import * as logger from 'loglevel'; +let log = logger.getLogger('CryptoManager'); +/* +* This class provides some of the encryption and decryption logic of the messages, +* incoming and outgoing messages. +* NOTE: This class sould be threated (for now) as a internal class of CryptoManager, since it +* receives and changes fields of that tsame class, but its on a sepetare file to +* ease code organization. +*/ class MessageEncryptionHandling { - constructor(registry, chatKeys, crypto, idm, storageManager, dataObjectsStorage) { + constructor(registry, chatKeys, crypto, storageManager, dataObjectsStorage) { this.registry = registry; this.chatKeys = chatKeys; this.crypto = crypto; - this.idm = idm; this.storageManager = storageManager; this.dataObjectsStorage = dataObjectsStorage; } encryptBetweenHyperties(message) { let _this = this; - console.log('xxx2'); return new Promise((resolve, reject) => { let userURL = _this.registry.getHypertyOwner(message.from); @@ -25,9 +32,9 @@ class MessageEncryptionHandling { // check if exists any keys between two users let chatKeys = _this.chatKeys[message.from + '<->' + message.to]; if (!chatKeys) { - chatKeys = _this._newChatCrypto(message, userURL); + chatKeys = _this.newChatCrypto(message, userURL); - //console.log('createChatKey encrypt', message.from + message.to); + //log.log('createChatKey encrypt', message.from + message.to); _this.chatKeys[message.from + '<->' + message.to] = chatKeys; message.body.handshakePhase = 'startHandShake'; } @@ -41,7 +48,7 @@ class MessageEncryptionHandling { stringify(iv), chatKeys.hypertyFrom.messageInfo); _this.crypto.hashHMAC(chatKeys.keys.hypertyFromHashKey, filteredMessage).then(hash => { - //console.log('result of hash ', hash); + //log.log('result of hash ', hash); let value = {iv: encode(iv), value: encode(encryptedValue), hash: encode(hash)}; message.body.value = encode(value); @@ -105,8 +112,6 @@ class MessageEncryptionHandling { let filteredMessage = filterMessageToHash(message, stringifiedMessageBody + stringifiedIV); _this.crypto.hashHMAC(dataObjectKey.sessionKey, filteredMessage).then(hash => { - // console.log('hash ', hash); - let newValue = {value: encode(encryptedValue), iv: encode(iv), hash: encode(hash)}; message.body.value = stringify(newValue); @@ -139,7 +144,7 @@ class MessageEncryptionHandling { let chatKeys = _this.chatKeys[message.to + '<->' + message.from]; if (!chatKeys) { - chatKeys = _this._newChatCrypto(message, userURL, 'decrypt'); + chatKeys = _this.newChatCrypto(message, userURL, 'decrypt'); _this.chatKeys[message.to + '<->' + message.from] = chatKeys; } @@ -149,17 +154,17 @@ class MessageEncryptionHandling { let data = decodeToUint8Array(value.value); let hash = decodeToUint8Array(value.hash); _this.crypto.decryptAES(chatKeys.keys.hypertyToSessionKey, data, iv).then(decryptedData => { - // console.log('decrypted value ', decryptedData); + // log.log('decrypted value ', decryptedData); message.body.value = decryptedData; let filteredMessage = filterMessageToHash(message, decryptedData + iv); _this.crypto.verifyHMAC(chatKeys.keys.hypertyToHashKey, filteredMessage, hash).then(result => { - console.log('Result of hash verification in decryptMessage: ', result); + log.log('Result of hash verification in decryptMessage: ', result); message.body.assertedIdentity = true; resolve({message: message, isHandShakeNeeded: false}); }).chatch(err => { - console.log('decryptMessage HMAC failed:', err); + log.log('decryptMessage HMAC failed:', err); throw err; }); }); @@ -195,15 +200,11 @@ class MessageEncryptionHandling { _this.crypto.decryptAES(dataObjectKey.sessionKey, encryptedValue, iv).then(decryptedValue => { let parsedValue = parse(decryptedValue); - - // console.log('decrypted Value,', parsedValue); message.body.value = parsedValue; - let filteredMessage = filterMessageToHash(message, stringify(parsedValue) + stringify(iv)); _this.crypto.verifyHMAC(dataObjectKey.sessionKey, filteredMessage, hash).then(result => { - console.log('Received message HMAC result', result); - + log.log('Received message HMAC result', result); message.body.assertedIdentity = true; resolve(message); }).catch(err => { reject('Message HMAC is invalid: ' + err); }); @@ -226,8 +227,7 @@ class MessageEncryptionHandling { } - - /** +/** * generates the initial structure for the keys between two users * @param {JSON} message initial message that triggers the mutual authentication * @param {String} userURL userURL @@ -235,8 +235,7 @@ class MessageEncryptionHandling { * @return {JSON} newChatCrypto new JSON structure for the chat crypto */ - _newChatCrypto(message, userURL, receiver) { - let _this = this; + newChatCrypto(message, userURL, receiver, userInfo) { //check whether is the sender or the receiver to create a new chatCrypto //to mantain consistency on the keys if the receiver create a new chatCrypto, @@ -244,8 +243,6 @@ class MessageEncryptionHandling { let from = (receiver) ? message.to : message.from; let to = (receiver) ? message.from : message.to; - let userInfo = _this.idm.getIdentity(userURL); - let newChatCrypto = { hypertyFrom: @@ -293,68 +290,4 @@ class MessageEncryptionHandling { } -/** - * Identifies the messages to be encrypted - * @param {Message} message - * @returns {boolean} returns true if the message requires encryption - */ - -export function isToEncrypt(message) { - console.info('[CryptoManager.istoChyperModule]', message); - let isCreate = message.type === 'create'; - let isFromHyperty = message.from.includes('hyperty://'); - let isToHyperty = message.to.includes('hyperty://'); - let isToDataObject = isDataObjectURL(message.to); - - let doMutualAuthentication = message.body.hasOwnProperty('mutual') ? message.body.mutual : true; - - if (!doMutualAuthentication) return false; - - //if is not to apply encryption, then returns resolve - if (!this.isToUseEncryption && !(message.type === 'handshake')) { - console.info('not handshake: encryption disabled'); - return false; - } - - if (message.type === 'update') { - console.info('update:encryption disabled'); - return false; - } - - if (isLegacy(message.to)) return false; - - return ((isCreate && isFromHyperty && isToHyperty) || (isCreate && isFromHyperty && isToDataObject && doMutualAuthentication) || message.type === 'handshake' || (message.type === 'update' && doMutualAuthentication)); -} - - -export function isToDecrypt(message) { - let _this = this; - - return new Promise((resolve, reject) => { - // For sybscribe message let's start the mutualAuthentication - let isSubscription = message.type === 'subscribe'; - let isFromRemoteSM = _this._isFromRemoteSM(message.from); - - if (isSubscription & isFromRemoteSM) { - console.log('_doMutualAuthenticationPhase1'); - - _this._doMutualAuthenticationPhase1(message).then(() => { - resolve(false); - }, (error) => { - reject(error); - }); - - } else if (message.hasOwnProperty('body') && message.body.hasOwnProperty('value') && typeof message.body.value === 'string') { - console.log('_isToDecrypt:true'); - resolve(true); - } else { - console.log('_isToDecrypt:false'); - resolve(false); - } - - }).catch((error) => { - console.error('[CryptoManager._isToDecrypt]', error); - }); -} - -module.exports = MessageEncryptionHandling; +export default MessageEncryptionHandling; From bd41a9d97c4a7c5215d36c40033c929769d4e58d Mon Sep 17 00:00:00 2001 From: Joao Lopes Date: Thu, 15 Feb 2018 18:01:59 +0000 Subject: [PATCH 11/15] Commented not working tests --- dist/PEP.js | 862 +----------- dist/ReThinkCtx.js | 458 +------ dist/Runtime.js | 87 +- dist/Runtime.light.js | 1215 +++++++++++++++++ dist/Runtime.min.js | 1215 +++++++++++++++++ dist/minibus.js | 695 +--------- dist/sandbox.js | 712 +--------- src/cryptoManager/Crypto.js | 3 +- src/cryptoManager/CryptoManager.js | 18 +- .../MessageEncryptionHandling.js | 22 +- src/identity/Identities.js | 1 + src/identity/IdentityModule.js | 16 +- test/IdentityModule.spec.js | 341 ++--- 13 files changed, 2616 insertions(+), 3029 deletions(-) mode change 100644 => 100755 dist/PEP.js mode change 100644 => 100755 dist/ReThinkCtx.js mode change 100644 => 100755 dist/Runtime.js mode change 100644 => 100755 dist/Runtime.light.js mode change 100644 => 100755 dist/Runtime.min.js mode change 100644 => 100755 dist/minibus.js mode change 100644 => 100755 dist/sandbox.js diff --git a/dist/PEP.js b/dist/PEP.js old mode 100644 new mode 100755 index 5dac6965..d6787547 --- a/dist/PEP.js +++ b/dist/PEP.js @@ -1,5 +1,5 @@ // version: 0.11.1 -// date: Thu Jan 18 2018 13:05:27 GMT+0000 (WET) +// date: Thu Feb 08 2018 14:02:26 GMT+0000 (WET) // licence: /** * Copyright 2016 PT Inovação e Sistemas SA @@ -26,7 +26,7 @@ // version: 0.11.1 -// date: Thu Jan 18 2018 13:05:27 GMT+0000 (WET) +// date: Thu Feb 08 2018 14:02:26 GMT+0000 (WET) // licence: /** * Copyright 2016 PT Inovação e Sistemas SA @@ -52,860 +52,4 @@ **/ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("PEP",[],t):"object"==typeof exports?exports.PEP=t():e.PEP=t()}("undefined"!=typeof self?self:this,function(){/******/ -return function(e){/******/ -/******/ -// The require function -/******/ -function __webpack_require__(r){/******/ -/******/ -// Check if module is in cache -/******/ -if(t[r])/******/ -return t[r].exports;/******/ -// Create a new module (and put it into the cache) -/******/ -var n=t[r]={/******/ -i:r,/******/ -l:!1,/******/ -exports:{}};/******/ -/******/ -// Return the exports of the module -/******/ -/******/ -/******/ -// Execute the module function -/******/ -/******/ -/******/ -// Flag the module as loaded -/******/ -return e[r].call(n.exports,n,n.exports,__webpack_require__),n.l=!0,n.exports}// webpackBootstrap -/******/ -// The module cache -/******/ -var t={};/******/ -/******/ -// Load entry module and return exports -/******/ -/******/ -/******/ -/******/ -// expose the modules object (__webpack_modules__) -/******/ -/******/ -/******/ -// expose the module cache -/******/ -/******/ -/******/ -// define getter function for harmony exports -/******/ -/******/ -/******/ -// getDefaultExport function for compatibility with non-harmony modules -/******/ -/******/ -/******/ -// Object.prototype.hasOwnProperty.call -/******/ -/******/ -/******/ -// __webpack_public_path__ -/******/ -return __webpack_require__.m=e,__webpack_require__.c=t,__webpack_require__.d=function(e,t,r){/******/ -__webpack_require__.o(e,t)||/******/ -Object.defineProperty(e,t,{/******/ -configurable:!1,/******/ -enumerable:!0,/******/ -get:r})},__webpack_require__.n=function(e){/******/ -var t=e&&e.__esModule?/******/ -function(){return e.default}:/******/ -function(){return e};/******/ -/******/ -return __webpack_require__.d(t,"a",t),t},__webpack_require__.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},__webpack_require__.p="",__webpack_require__(__webpack_require__.s=118)}([/* 0 */ -/***/ -function(e,t){var r=e.exports={version:"2.5.3"};"number"==typeof __e&&(__e=r)},/* 1 */ -/***/ -function(e,t){ -// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 -var r=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=r)},/* 2 */ -/***/ -function(e,t,r){var n=r(28)("wks"),o=r(19),i=r(1).Symbol,u="function"==typeof i;(e.exports=function(e){return n[e]||(n[e]=u&&i[e]||(u?i:o)("Symbol."+e))}).store=n},/* 3 */ -/***/ -function(e,t,r){var n=r(1),o=r(0),i=r(14),u=r(8),a=function(e,t,r){var s,c,f,l=e&a.F,p=e&a.G,d=e&a.S,v=e&a.P,y=e&a.B,h=e&a.W,_=p?o:o[t]||(o[t]={}),g=_.prototype,m=p?n:d?n[t]:(n[t]||{}).prototype;p&&(r=t);for(s in r) -// contains in native -(c=!l&&m&&void 0!==m[s])&&s in _||( -// export native or passed -f=c?m[s]:r[s], -// prevent global pollution for namespaces -_[s]=p&&"function"!=typeof m[s]?r[s]:y&&c?i(f,n):h&&m[s]==f?function(e){var t=function(t,r,n){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,r)}return new e(t,r,n)}return e.apply(this,arguments)};return t.prototype=e.prototype,t}(f):v&&"function"==typeof f?i(Function.call,f):f, -// export proto methods to core.%CONSTRUCTOR%.methods.%NAME% -v&&((_.virtual||(_.virtual={}))[s]=f, -// export proto methods to core.%CONSTRUCTOR%.prototype.%NAME% -e&a.R&&g&&!g[s]&&u(g,s,f)))}; -// type bitmap -a.F=1,// forced -a.G=2,// global -a.S=4,// static -a.P=8,// proto -a.B=16,// bind -a.W=32,// wrap -a.U=64,// safe -a.R=128,// real proto method for `library` -e.exports=a},/* 4 */ -/***/ -function(e,t,r){var n=r(6);e.exports=function(e){if(!n(e))throw TypeError(e+" is not an object!");return e}},/* 5 */ -/***/ -function(e,t,r){ -// Thank's IE8 for his funny defineProperty -e.exports=!r(13)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},/* 6 */ -/***/ -function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},/* 7 */ -/***/ -function(e,t,r){var n=r(4),o=r(36),i=r(26),u=Object.defineProperty;t.f=r(5)?Object.defineProperty:function(e,t,r){if(n(e),t=i(t,!0),n(r),o)try{return u(e,t,r)}catch(e){}if("get"in r||"set"in r)throw TypeError("Accessors not supported!");return"value"in r&&(e[t]=r.value),e}},/* 8 */ -/***/ -function(e,t,r){var n=r(7),o=r(18);e.exports=r(5)?function(e,t,r){return n.f(e,t,o(1,r))}:function(e,t,r){return e[t]=r,e}},/* 9 */ -/***/ -function(e,t){var r={}.hasOwnProperty;e.exports=function(e,t){return r.call(e,t)}},/* 10 */ -/***/ -function(e,t,r){ -// to indexed object, toObject with fallback for non-array-like ES3 strings -var n=r(57),o=r(22);e.exports=function(e){return n(o(e))}},/* 11 */ -/***/ -function(e,t,r){"use strict";t.__esModule=!0,t.default=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},/* 12 */ -/***/ -function(e,t,r){"use strict";t.__esModule=!0;var n=r(60),o=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default=function(){function defineProperties(e,t){for(var r=0;r0?n:r)(e)}},/* 22 */ -/***/ -function(e,t){ -// 7.2.1 RequireObjectCoercible(argument) -e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},/* 23 */ -/***/ -function(e,t){e.exports=!0},/* 24 */ -/***/ -function(e,t,r){var n=r(7).f,o=r(9),i=r(2)("toStringTag");e.exports=function(e,t,r){e&&!o(e=r?e:e.prototype,i)&&n(e,i,{configurable:!0,value:t})}},/* 25 */ -/***/ -function(e,t,r){var n=r(6),o=r(1).document,i=n(o)&&n(o.createElement);e.exports=function(e){return i?o.createElement(e):{}}},/* 26 */ -/***/ -function(e,t,r){ -// 7.1.1 ToPrimitive(input [, PreferredType]) -var n=r(6); -// instead of the ES6 spec version, we didn't implement @@toPrimitive case -// and the second argument - flag - preferred type is a string -e.exports=function(e,t){if(!n(e))return e;var r,o;if(t&&"function"==typeof(r=e.toString)&&!n(o=r.call(e)))return o;if("function"==typeof(r=e.valueOf)&&!n(o=r.call(e)))return o;if(!t&&"function"==typeof(r=e.toString)&&!n(o=r.call(e)))return o;throw TypeError("Can't convert object to primitive value")}},/* 27 */ -/***/ -function(e,t,r){var n=r(28)("keys"),o=r(19);e.exports=function(e){return n[e]||(n[e]=o(e))}},/* 28 */ -/***/ -function(e,t,r){var n=r(1),o=n["__core-js_shared__"]||(n["__core-js_shared__"]={});e.exports=function(e){return o[e]||(o[e]={})}},/* 29 */ -/***/ -function(e,t){ -// IE 8- don't enum bug keys -e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},/* 30 */ -/***/ -function(e,t,r){ -// 7.1.13 ToObject(argument) -var n=r(22);e.exports=function(e){return Object(n(e))}},/* 31 */ -/***/ -function(e,t,r){ -// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) -var n=r(4),o=r(69),i=r(29),u=r(27)("IE_PROTO"),a=function(){},s=function(){ -// Thrash, waste and sodomy: IE GC bug -var e,t=r(25)("iframe"),n=i.length;for(t.style.display="none",r(46).appendChild(t),t.src="javascript:",// eslint-disable-line no-script-url -// createDict = iframe.contentWindow.Object; -// html.removeChild(iframe); -e=t.contentWindow.document,e.open(),e.write("