-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Symmetric keygen: JsThemis #562
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,7 @@ describe("jsthemis", function(){ | |
decrypter = new addon.SecureMessage(peer_keypair.private(), keypair.public()); | ||
intruder_decrypter = new addon.SecureMessage(intruder_keypair.private(), keypair.public()); | ||
message = new Buffer("Test Message"); | ||
it("encrypt/decrypt", function(){ | ||
it("encrypt/decrypt", function(){ | ||
encrypted_message = encrypter.encrypt(message); | ||
assert.equal(message.toString(), decrypter.decrypt(encrypted_message).toString()); | ||
assert.throws(function(){intruder_decrypter.decrypt(encrypted_message);}, expect_code(addon.FAIL)); | ||
|
@@ -86,7 +86,7 @@ describe("jsthemis", function(){ | |
server_keypair = new addon.KeyPair(); | ||
client_id = new Buffer("client"); | ||
client_keypair = new addon.KeyPair(); | ||
|
||
server_session = new addon.SecureSession(server_id, server_keypair.private(), function(id){ | ||
if(id.toString()=="server") | ||
return server_keypair.public(); | ||
|
@@ -175,6 +175,28 @@ describe("jsthemis", function(){ | |
|
||
describe("jsthemis", function(){ | ||
describe("secure cell", function(){ | ||
describe("key generation", function(){ | ||
const defaultLength = 32 | ||
it("generates new key buffer", function(){ | ||
var masterKey = new addon.SymmetricKey() | ||
assert.equal(masterKey.length, defaultLength) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually here not checked that generated new key buffer. we should compare references/values to be sure, not that same length was used. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mmm... I’d say this is a bit excessive. But sure, we can add var key1 = new addon.SymmetricKey()
var key2 = new addon.SymmetricKey()
assert.notDeepEqual(key1, key2) // checks that content is not the same
assert.notEqual(key1, key2) // checks that objects are distinct Though I doubt that this test will prevent any coding mistakes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like to add it because we should be sure that our new layer of js code correctly uses themis core. If it was simple proxying calls like in c++/golang then it will be really overhead. But in wrappers like jsthemis/phpthemis where we deal with language wrapper API we should do more checks IMHO because we have more places for mistakes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, now I get your point. That’s a pretty valid concern. Thank you for the explanation. |
||
}) | ||
it("is able to restore SymmetricKey from bytes", function(){ | ||
var bytes = Buffer.from("MDRwUzB0NG1aN2pvTEEwdVljRFJ5", "base64") | ||
var masterKey = new addon.SymmetricKey(bytes) | ||
assert.equal(masterKey.length, bytes.length) | ||
}) | ||
it("throws on empty buffer", function(){ | ||
assert.throws(() => new addon.SymmetricKey(Buffer.from("")), | ||
vixentael marked this conversation as resolved.
Show resolved
Hide resolved
|
||
expect_code(addon.INVALID_PARAMETER)) | ||
assert.throws(() => new addon.SymmetricKey(""), | ||
expect_code(addon.INVALID_PARAMETER)) | ||
assert.throws(() => new addon.SymmetricKey(null), | ||
expect_code(addon.INVALID_PARAMETER)) | ||
assert.throws(() => new addon.SymmetricKey(undefined), | ||
expect_code(addon.INVALID_PARAMETER)) | ||
}) | ||
}) | ||
message=new Buffer("This is test message"); | ||
password=new Buffer("This is test password"); | ||
context=new Buffer("This is test context"); | ||
|
@@ -217,7 +239,7 @@ describe("jsthemis", function(){ | |
context_imprint_intruder_decrypter = new addon.SecureCellContextImprint(new Buffer("This is test password1")); | ||
assert.throws(function(){new addon.SecureCellContextImprint(empty_message)}); | ||
context_imprint_enc_data = context_imprint_encrypter.encrypt(message, context); | ||
assert.equal(message.length, context_imprint_enc_data.length); | ||
assert.equal(message.length, context_imprint_enc_data.length); | ||
context_imprint_dec_data = context_imprint_decrypter.decrypt(context_imprint_enc_data, context); | ||
assert.equal(message.toString(), context_imprint_dec_data.toString()); | ||
context_imprint_dec_data = context_imprint_intruder_decrypter.decrypt(context_imprint_enc_data, context); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if user pass own buffer, why we don't reuse it and return new allocated buffer?
CopyIntoBuffer use nan::CopyBuffer instead nan::NewBuffer which will reuse passed array
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I re-read comments and understand that we just copy passed buffer, not generate new key... but for what we do this or why it will useful for user? is I understand correctly, that when user pass some Buffer to constructor
themis.SymmetricKey(someBuffer)
we return node::Bufer object with same values?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, we have to copy the buffer so that changes in the original buffer do not affect the key.
As for why this API exists at all, my original idea was that
new themis.SymmetricKey(...)
would return an instance of SymmetricKey — a type that inherits from Buffer, but is not a Buffer. Then it will be possible to restrict Secure Cell interfaces to work only with SymmetricKey instances which are guaranteed to contain only valid keys. In this case the users will need an ability to convert an arbitrary Buffer into SymmetricKey with JsThemis validating the key.Currently new themis.SymmetricKey() returns instances of buffer, but even if that’s not fixed by the next release I would like to keep this API so that we teach the users to use it instead of using Buffers directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as I see,
nan
and nodejs buffer api provide two ways to create objects. New created with copy of valuesnan::FromBuffer
and second way to reuse user's objectnew nan::NewBuffer
. What about to be appropriate with their api and provide two ways too?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nan::NewBuffer()
transfers the ownership over achar*
buffer to Node.js Buffer object. That’s not what we want here since the original byte buffer is still owned by the original Buffer object. It’s a utility method to transfer buffers created by C++ code into JavaScript without making an unnecessary copy.When the user does
new SymmetricKey(someBuffer)
it does not transfer someBuffer into SymmetricKey. Unfortunately, JavaScript is not Rust and even if we did reuse an existing Buffer as SymmetricKey, this will not prevent the user from usingsomeBuffer
again after the call. For example, they could modify the buffer and this will modify the key. I don’t think that this spooky action at the distance is an expected behavior so it’s better to copy the buffer withNan::CopyBuffer()
and avoid such issues.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's okay if they know, that they transfer ownership. in such case they use
new SymmetricKey(someBuffer)
just to cast their buffer to correct type to use with themis in the future. If our function doesn't modify this buffer, it's okay if user use previously created object to re-use if he know, that don't need it in a future. For example (js pseudocode):here is user reuse same buffer and use it just to cast his keys to correct type and use with themis SecureCell api.
But if we can't do like that, so we only can leave as is...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above code will work just fine. That's what a sane developer (i.e., one thinking like me) would probably write if they wanted to encrypt data with different keys.
The current copying implementation makes the following usage impossible:
While it definitely has a rationale of a sort, I'd consider it premature optimization and, honestly, a sleeping footgun. It looks like the same cell is used for encryption while in fact the key is different.
Now imagine if the Buffer is actually a reference that's kept in a field or some object. And that object caches buffer instances so the same buffer may be reused later for some completely unrelated data. Even if you don't abuse the buffer like the above, it may still be accidentally changed.
That's why I think that copying the buffer is the most reasonable choice here.