Comments (37)
with #59 we should get a speedup
from pbkdf2.
ping @feross, thoughts on whether this might be a Buffer issue before I dig into it deeper?
from pbkdf2.
You can check if the buffer instances are based on Uint8Array
with buf instanceof Uint8Array
or if we detect typed array support Buffer.TYPED_ARRAY_SUPPORT
as defined here. If those are false
, then you're getting the fallback Object implementation.
Safari 7 and below has a bug in Object.prototype.constructor
, so we're just using the Object implementation instead of adding a workaround, as described here: feross/buffer#63 Perhaps this is the issue?
from pbkdf2.
I'm willing to look into this soon.
from pbkdf2.
Safari 5-7 get the Uint8Array implementation as of the latest buffer version! So you might not even need to fix this anymore.
from pbkdf2.
@feross it actually seems related to the fact that createHmac
is creating a new Buffer
every time compared to SJCL which re-uses the underlying array.
I'm not sure if this is avoidable without breaking compliance in the create*
modules?
from pbkdf2.
E.g https://github.com/crypto-browserify/sha.js/blob/master/sha1.js#L84-L94
from pbkdf2.
Not sure what you're trying to do, but if you want to create a buffer without allocating a whole new Uint8Array, you can now do this in node.js and the browser:
var buf1 = new Buffer(4)
var buf2 = new Buffer(buf1.buffer)
buf1
and buf2
now share the same underlying ArrayBuffer
instance.
from pbkdf2.
@feross no no, my point is, look at sha1.js
, we are creating a new Buffer
each time we digest
. There is no way to inject a .buffer
in there without breaking compliance with node? No?
from pbkdf2.
Since iojs v3 and node v4, Buffer
is a subclass of Uint8Array
. So .buffer
should work just fine!
from pbkdf2.
@feross I don't understand.
How is that relevant?
from pbkdf2.
I'm talking about .digest()
from pbkdf2.
In https://github.com/crypto-browserify/sha.js/blob/master/hash.js#L41,
Hash.prototype.digest = function (enc) {
Would have to become
Hash.prototype.digest = function (enc, target) {
Where target
is an optional target Buffer
.
This would not be compliant with node
/io
, AFAIK.
from pbkdf2.
I'm probably misunderstanding something here, just ignore me. ¯\_(ツ)_/¯
from pbkdf2.
Ah, I see your point. Yeah that sounds like it's an API modification.
from pbkdf2.
@rubensayshi our only options at this point would be to replace the entire underlying implementation with a different HMAC stack. I'm not really keen on that.
How are the benchmarks holding up?
from pbkdf2.
Results with improved sha.js (2.4.5), pbkdf2 (3.0.4)
Google Chrome Version 49.0.2623.63 beta (64-bit)
sjcl.misc.pbkdf2 462 = 92.4
build.js:24059 pbkdf2.pbkdf2Sync 2599 = 519.8
Firefox 44.0.2 (64-bit)
sjcl.misc.pbkdf2 383 = 76.6
pbkdf2.pbkdf2Sync 2988 = 597.6
node.js v5.6.0 (using browser version)
sjcl.misc.pbkdf2 415 = 83
pbkdf2.pbkdf2Sync 1893 = 378.6
from pbkdf2.
Awesome.
from pbkdf2.
ping @fanatid we could also improve speed by somehow caching the ipad/opad
values and their resultant base hash.
They are currently re-calculated every time.
from pbkdf2.
@fanatid thoughts?
Here is some mock up example code I did in C++ where I take advantage of this trick to basically double the speed (twice as fast as OpenSSL):
#include <cassert>
#include <cstdint>
#include <cstring>
#include <openssl/sha.h>
#include <openssl/evp.h>
#define SHA256_DIGEST_LENGTH 32
void pbkdf2_hmac_sha256 (const uint8_t* password, const size_t passwordLength, const uint8_t* salt, const size_t saltLength, const size_t iterations, uint8_t* key, size_t keyLength) {
SHA256_CTX ipadCtx, opadCtx;
// pre-calculate the HMAC blocks to avoid constant re-calculation
{
uint8_t ipad[SHA256_CBLOCK], opad[SHA256_CBLOCK];
memset(ipad, 0x36, SHA256_CBLOCK);
memset(opad, 0x5C, SHA256_CBLOCK);
if (passwordLength > SHA256_CBLOCK) {
uint8_t tmp[SHA256_DIGEST_LENGTH];
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, password, passwordLength);
SHA256_Final(tmp, &ctx);
for (size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
ipad[i] ^= tmp[i];
opad[i] ^= tmp[i];
}
} else {
for (size_t i = 0; i < passwordLength; i++) {
ipad[i] ^= password[i];
opad[i] ^= password[i];
}
}
SHA256_Init(&ipadCtx);
SHA256_Init(&opadCtx);
SHA256_Update(&ipadCtx, ipad, SHA256_CBLOCK);
SHA256_Update(&opadCtx, opad, SHA256_CBLOCK);
}
// divide and round upwards
auto l = keyLength / SHA256_DIGEST_LENGTH;
if (keyLength % SHA256_DIGEST_LENGTH != 0) l += 1;
const auto r = keyLength - (l - 1) * SHA256_DIGEST_LENGTH;
uint8_t T[SHA256_DIGEST_LENGTH], U[SHA256_DIGEST_LENGTH];
// TODO: REMOVE write32BE 8-bit shortcut
uint8_t uint32BE[4] = {};
for (size_t i = 1; i <= l; i++) {
// TODO: REMOVE write32BE 8-bit shortcut
assert(i < 256);
uint32BE[3] = (uint8_t) i;
SHA256_CTX ctx;
memcpy(&ctx, &ipadCtx, sizeof(SHA256_CTX));
SHA256_Update(&ctx, salt, saltLength);
SHA256_Update(&ctx, &uint32BE, sizeof(uint32BE));
SHA256_Final(U, &ctx);
memcpy(&ctx, &opadCtx, sizeof(SHA256_CTX));
SHA256_Update(&ctx, U, SHA256_DIGEST_LENGTH);
SHA256_Final(U, &ctx);
memcpy(T, U, SHA256_DIGEST_LENGTH);
for (size_t j = 1; j < iterations; j++) {
memcpy(&ctx, &ipadCtx, sizeof(SHA256_CTX));
SHA256_Update(&ctx, U, SHA256_DIGEST_LENGTH);
SHA256_Final(U, &ctx);
memcpy(&ctx, &opadCtx, sizeof(SHA256_CTX));
SHA256_Update(&ctx, U, SHA256_DIGEST_LENGTH);
SHA256_Final(U, &ctx);
for (size_t k = 0; k < SHA256_DIGEST_LENGTH; k++) T[k] ^= U[k];
}
const auto destPos = (i - 1) * SHA256_DIGEST_LENGTH;
const auto len = (i == l ? r : SHA256_DIGEST_LENGTH);
memcpy(key + destPos, T, len);
}
}
#include <iomanip>
#include <iostream>
int main (int argc, char** argv) {
const uint8_t k[] = "password_________________________________________________________________________________________________________________________";
const uint8_t s[] = "salt bbbbbbbbbbbbbb";
const int kl = sizeof(k) - 1;
const int sl = sizeof(s) - 1;
// ours
{
uint8_t buffer[10];
pbkdf2_hmac_sha256(k, kl, s, sl, 2000, buffer, sizeof(buffer));
for (size_t i = 0; i < sizeof(buffer); ++i) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (unsigned) buffer[i] << ' ';
}
std::cout << std::endl;
}
// openssl
{
uint8_t buffer[10];
PKCS5_PBKDF2_HMAC(
(const char*) k, kl,
s, sl,
2000,
EVP_sha256(),
sizeof(buffer),
buffer
);
for (size_t i = 0; i < sizeof(buffer); ++i) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (unsigned) buffer[i] << ' ';
}
std::cout << std::endl;
}
return 0;
}
from pbkdf2.
@dcousens yep, we can cache it and I sure that it gives significant performance improvement, but it will be not easy and could be easily broken by createHash
from pbkdf2.
@fanatid granted, but this doesn't have to rely on create-hash
if the API isn't suitable.
from pbkdf2.
we could also look back into using subtle crypto in the places that support it
from pbkdf2.
@calvinmetcalf is that faster?
from pbkdf2.
it's native so yes it would be, you could test with native-crypto which (in the browser) uses that if it's available and then this if not
from pbkdf2.
Is this still a concern?
from pbkdf2.
not for me, using asmcrypto.js ;)
from pbkdf2.
Can you post a bench? It might be worth dropping it in.
from pbkdf2.
Thanks @calvinmetcalf , forgot about it.
Merged :)
Still be worth comparing though :)
from pbkdf2.
oh yes I agree, I think I'll also publish all 3 of the updates we have in the wings
from pbkdf2.
Tested this today.
sjcl
is 1.6x faster.
asmcrypto.js
is 4x faster.
If we omit the new changes, sjcl
is about 5x faster...
Win!
But haven't won the war yet.
asmcrypto.js
is going to be hard to beat...
from pbkdf2.
I don't think we'd ever beat asmcrypto.js
without breaking module isolation.
It inlines the ipad
/opad
directly... https://github.com/vibornoff/asmcrypto.js/blob/master/src/hash/sha256/sha256.asm.js#L745
from pbkdf2.
are you testing async in a browser because I bet we're faster there
from pbkdf2.
@calvinmetcalf because of webcrypto
?
from pbkdf2.
from pbkdf2.
oh wow seems I've missed the webcrypto support addition, nice!
from pbkdf2.
Closing in favour of #75
from pbkdf2.
Related Issues (20)
- why we need to check crypto.pbkdf2Sync.toString() ? HOT 2
- In 9.0.0, sha1 is not defaulted HOT 2
- Ripemd160 throws when used HOT 1
- Allow using this library with Uint8Array HOT 2
- DoS with long password HOT 5
- How to improve the performance HOT 2
- works on browser? HOT 2
- Can I decode it?
- version change from 3.0.7 to 3.1.0 HOT 6
- pbkdf2.pbkdf2Sync('password', 'salt', 1, 32, 'sha512') returns array not string HOT 1
- The value "NaN" is invalid for option "size" HOT 2
- Uint8Array tests fail on s390x
- Incompatibility with rn-nodeify HOT 5
- Issue in pbkdf2/lib/default-encoding.js HOT 1
- process.version is undefined in lib/default-encoding.js on electron app
- pbkdf2\lib\default-encoding.js, process.version is undefine,
- In the electronic application, when I start nodeintegration, the program appears default-encoding.js? 9f9d:10 Uncaught TypeError: Cannot read property 'split' of undefined HOT 1
- pbkdf2 failing on some development environments
- pbkdf2\lib\default-encoding.js, Unexpected token (5:36) HOT 1
- Please consider upgrading the default hash function
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pbkdf2.