The attacker would just have to know that a user was using a certain app, right?
Does it depend also on the fake app persuading the user to authorise it - and therefore also to run it?
This and the above points are going to be really important arenât they! We need to put together a guide on recommended procedures and what they do /donât guarantee.
Yes, just send me a PM.
This would indeed be interesting. If itâs not the case Iâm really starting to think that we need something like a getUserEncKey method. Which brings me back to my previous question:
As I understand, reading the MD RFC, the READ of and MD, even private, is not blocked so anybody can ask for this data if they know the direction and TypeTag. The protection for this data, if private, is the symmetric or asymmetric encryption. So I you share with somebody the relevant information (direction, TypeTag and decrypt Key) I see no impediment to read this data.
@Mindphreaker While digging around in core libraries I saw that ClientKeys
struct has a symmetric encryption key. Will follow this path to see where a clientâs symmetric encryption key is used. I wonder if this is a candidate, and if it would be sensible, for exposure in our APIâs.
Check it out: https://github.com/maidsafe/safe_client_libs/blob/master/safe_core/src/client/account.rs#L133
I continued to experiment with your example from above @hunterlester and it seems, that Iâm able to fetch the stored value but only until I reauthenticate the app (e.g. reload the tab and reauthenticate). After reauthentication I noticed two things:
- The generated nonce is different, however the returned mdHandle from newPrivate still seems to be valid because the item count matches. I donât know if the nonce passed to newPrivate has an impact on de-/encryption.
- When calling encryptKey() I get a different return value compared to the time before reauthentication. This of course explains why I canât fetch the stored value. As long as I donât reload the page and donât reauthenticate the encryptKey() returns the same value.
Can you confirm this or do you know why this is happening?
I updated my code to use getAppPubEncKey
instead of getAppPubSignKey
.
This is working nicely.
I ran this code, then reloaded page and reauthenticated my application, retrieved the same private MD, and was able to successfully decrypt using the appâs public encryption key.
let appInfo = {
id: 'net.maidsafe.api_playground.webclient.10',
name: 'SAFE web API playground',
vendor: 'MaidSafe Ltd.',
scope: null
};
let encryptedEntries = {};
function decryptQueue(mdHandle, i) {
let entries = Object.keys(encryptedEntries);
if ( i === entries.length ) {
console.log('Decrypted entry: ', encryptedEntries);
return;
}
window.safeMutableData.decrypt(mdHandle, encryptedEntries[entries[i]].buf).then(decryptedValue => {
encryptedEntries[entries[i]] = String.fromCharCode.apply(null, new Uint8Array(decryptedValue));
decryptQueue(mdHandle, i + 1);
})
}
window.safeApp.initialise(appInfo).then(appHandle => window.safeApp.authorise(appHandle, {
_public: ['Read', 'Insert', 'Update', 'Delete'],
_publicNames: ['Read', 'Insert', 'Update', 'Delete']
}, { own_container: true })
.then(authUri => window.safeApp.connectAuthorised(appHandle, authUri)))
.then(appHandle => window.safeCrypto.sha3Hash(appHandle, 'explicitly_named_md')
.then(hashedString => ({hashedString, appHandle})))
.then(({hashedString, appHandle}) => window.safeCrypto.getAppPubEncKey(appHandle)
.then(encKeyHandle => window.safeCryptoPubEncKey.getRaw(encKeyHandle).then(rawPubEncKey => ({rawPubEncKey, hashedString, appHandle}))))
.then(({rawPubEncKey, hashedString, appHandle}) => window.safeCrypto.generateNonce(appHandle).then(nonce => ({rawPubEncKey, hashedString, appHandle, nonce})))
.then(({rawPubEncKey, hashedString, appHandle, nonce}) => window.safeMutableData.newPrivate(appHandle, hashedString, 15001, rawPubEncKey.buffer, nonce.buffer)
.then(mdHandle => window.safeMutableData.encryptKey(mdHandle, 'key1').then(encryptedKey => ({encryptedKey}))
.then(({encryptedKey}) => window.safeMutableData.encryptValue(mdHandle, 'encrypted value').then(encryptedValue => ({encryptedKey, encryptedValue}))
.then(({encryptedKey, encryptedValue}) => window.safeMutableData.quickSetup(mdHandle)
.then(() => window.safeMutableData.newMutation(appHandle)
.then(mutationHandle => window.safeMutableDataMutation.insert(mutationHandle, encryptedKey, encryptedValue)
.then(() => window.safeMutableData.applyEntriesMutation(mdHandle, mutationHandle).then(() => ({mdHandle, appHandle, hashedString})))
)
)
)
)
)
)
.then(({mdHandle, appHandle, hashedString}) => window.safeMutableData.getEntries(mdHandle)
.then(entriesHandle => window.safeMutableDataEntries.forEach(entriesHandle, (k, v) => {
let key = String.fromCharCode.apply(null, k);
let value = String.fromCharCode.apply(null, new Uint8Array(v.buf));
console.log('Key: ', key,',', 'Value: ', value);
}).then(() => ({appHandle, hashedString}))
))
.then(({appHandle, hashedString}) => window.safeCrypto.getAppPubEncKey(appHandle)
.then(encKeyHandle => window.safeCryptoPubEncKey.getRaw(encKeyHandle).then(rawPubEncKey => ({rawPubEncKey, hashedString, appHandle})))
.then(({rawPubEncKey, hashedString, appHandle}) => window.safeCrypto.generateNonce(appHandle).then(nonce => ({rawPubEncKey, hashedString, appHandle, nonce})))
.then(({rawPubEncKey, hashedString, appHandle, nonce}) => window.safeMutableData.newPrivate(appHandle, hashedString, 15001, rawPubEncKey.buffer, nonce.buffer))
.then(mdHandle => window.safeMutableData.getEntries(mdHandle)
.then(entriesHandle => window.safeMutableDataEntries.forEach(entriesHandle, (k, v) => {
Object.defineProperty(encryptedEntries, k, {value: v, writable: true, enumerable: true, configurable: true});
})).then(() => {
console.log(mdHandle);
decryptQueue(mdHandle,0);
})
)
)
Nonce should always be unique for security purposes. Iâm just learning about how this works. Thanks to @dirvine for passing along this link for education: https://www.lvh.io/posts/nonce-misuse-resistance-101.html
The critical security property of a nonce is that itâs never repeated under the same key. You can remember this by the mnemonic that a nonce is a ânumber used onceâ. If you were to repeat the nonce, the keystream would also repeat. That means that an attacker can take the two ciphertexts and XOR them to compute the XOR of the plaintexts.
Doesnât SAFE use EdDSA, which uses a deterministic nonce?
Also,
-
Can someone explain why
window.safeMutableData.newRandomPrivate
does not have the same cryptographic parameters aswindow.safeMutableData.newPrivate
? Or put differently: what cryptographic secret encryption key and nonce doesnewRandomPrivate
use so I can pass them tonewPrivate
another time?
I expected the difference between those functions just to be about the address being picked or not. -
What exactly does âprivate accessâ mean in the context of
newRandomPrivate
/newPrivate
? Iâm not able to find a description of this sort of terminology in the RFCs.
In the example getAppPubEncKey are used in symmetric encryption so, for security reasons, is better never reuse nonces. The EdDSA are for asymmetric encryption.
The determinism of Nonce doesnât matter - they should not be repeated for a key. If you use something deterministic then you donât need to store it along with cipher text. If random then of you would store it along with cipher text. The nonce is stored plain-texted - so when you fetch data it will likely be combination of plain-texted Nonce and cipher text; then extract the Nonce and use it with the sec-sym-key to decrypt ciphertext.
We use this for our Nonce currently.
For MData: Private means the contents are encrypted, public means otherwise.
MDataInfo is a ptr to MData - containing sufficient info to fetch and read/update MData. It has XorName, type-tag, and enc-keys. _random()
function is to be used if you want everything random (you need to provide the type-tag though).
The other function _new()
is used if you want to provide your stuff. E.g. if you are designing an app where XorName is deterministic depending on user Input etc. If you want deterministic XorName but random keys, there are crypto functions in safe-app rust which you can use to obtain random keys and nonces and supply that along with your chosen XorName. Itâs just a matter of mix and match.
I agree with that, but if a nonce is not provided to fn enc_entry_key then a random one is generated which is not stored:
So, I donât understand how the data can be decrypted in this case.
The answer is explained in one of the posts that you âlikedâ - the 2nd point here
So entry-key encryption uses deterministic but unique nonce for all entries as opposed to entry-value which uses completely random nonce (and hence needs to be stored in the network along with the cipher text). With this clever trick we can get the great benefit of indexing. So if you know the MDataInfo (which you would need to know anyway to address a MData) and if you know your entry-key (which is why MData was invented in the first place - it can be used as a key-value store) - then all you need to do is create the deterministic nonce locally (using sha3(MDataInfo::nonce + entry-key)), use that along with your secret key (MDataInfo::key) to encrypt the entry-key get the cipher-text=Vec and ask for entry-value for that entry-key.
If entry-key nonce was also absolutely random like entry-valueâs nonce, then it would have to be stored along with cipher-textâed entry-key in the network and would be impossible to index it as key-value. You would then need to fetch all entry-key,value pairs and decode every entry-key until you get the expected one and only then see the value.
My concern was only about an implementation detail of the function I highlighted: the third parameter is an optional nonce. If none is provided by the caller then a random one is generated locally and is not stored globally and is not returned to the caller. So I thought it was lost.
My error was that I didnât pay attention that the nonce was serialized together with the ciphered text. Everything is ok, sorry for the disturbance.
Ah nw - probably worth bringing to notice is this PR, still in review. That removes the âoptionalityâ for Nonce if the Sec-Key is provided. It was optional for flexibility if in some case a user wanted an MDataInfo created with Secret-Key but no Nonce even for entry-keys (so that random one was used which would lead to inability to index) - but so far there has been no such use case and itâs just bloating logic with permutation. So we just decided to remove that (it was an option inside an option as you can see) and add it back only when required - the changes are internal and does not affect the API though.
This topic was automatically closed after 60 days. New replies are no longer allowed.