Which bcrypt cost to use for 2018?
Update
Actually it seems the benchmark was incorrectly setup I have followed the resource shared by user @Luke Joshua Park and now it works.
package main
import "testing"
func benchmarkBcrypt(i int, b *testing.B){
for n:= 0; n < b.N; n++ {
HashPassword("my pass", i)
}
}
func BenchmarkBcrypt9(b *testing.B){
benchmarkBcrypt(9, b)
}
func BenchmarkBcrypt10(b *testing.B){
benchmarkBcrypt(10, b)
}
func BenchmarkBcrypt11(b *testing.B){
benchmarkBcrypt(11, b)
}
func BenchmarkBcrypt12(b *testing.B){
benchmarkBcrypt(12, b)
}
func BenchmarkBcrypt13(b *testing.B){
benchmarkBcrypt(13, b)
}
func BenchmarkBcrypt14(b *testing.B){
benchmarkBcrypt(14, b)
}
Output:
BenchmarkBcrypt9-4 30 39543095 ns/op
BenchmarkBcrypt10-4 20 79184657 ns/op
BenchmarkBcrypt11-4 10 158688315 ns/op
BenchmarkBcrypt12-4 5 316070133 ns/op
BenchmarkBcrypt13-4 2 631838101 ns/op
BenchmarkBcrypt14-4 1 1275047344 ns/op
PASS
ok go-playground 10.670s
Old incorrect benchmark
I have a small set on benchmark test in golang and am curios of to what is a recommended bcrypt cost to use as of May 2018.
This is my benchrmark file:
package main
import "testing"
func BenchmarkBcrypt10(b *testing.B){
HashPassword("my pass", 10)
}
func BenchmarkBcrypt12(b *testing.B){
HashPassword("my pass", 12)
}
func BenchmarkBcrypt13(b *testing.B){
HashPassword("my pass", 13)
}
func BenchmarkBcrypt14(b *testing.B){
HashPassword("my pass", 14)
}
func BenchmarkBcrypt15(b *testing.B){
HashPassword("my pass", 15)
}
and this is HashPassword() func inside main.go:
import (
"golang.org/x/crypto/bcrypt"
)
func HashPassword(password string, cost int) (string, error) {
bytes, err := bcrypt.GenerateFromPassword(byte(password), cost)
return string(bytes), err
}
The current output is:
go test -bench=.
BenchmarkBcrypt10-4 2000000000 0.04 ns/op
BenchmarkBcrypt12-4 2000000000 0.16 ns/op
BenchmarkBcrypt13-4 2000000000 0.32 ns/op
BenchmarkBcrypt14-4 1 1281338532 ns/op
BenchmarkBcrypt15-4 1 2558998327 ns/op
PASS
It seems that for a bcrypt with cost of 13 the time it takes is 0.32 nanoseconds, and for cost 14 the time is 1281338532ns or ~1.2 seconds
Which I believe is too much. What do is the best bcrypt cost to use for the current year 2018.
go encryption hash bcrypt
|
show 3 more comments
Update
Actually it seems the benchmark was incorrectly setup I have followed the resource shared by user @Luke Joshua Park and now it works.
package main
import "testing"
func benchmarkBcrypt(i int, b *testing.B){
for n:= 0; n < b.N; n++ {
HashPassword("my pass", i)
}
}
func BenchmarkBcrypt9(b *testing.B){
benchmarkBcrypt(9, b)
}
func BenchmarkBcrypt10(b *testing.B){
benchmarkBcrypt(10, b)
}
func BenchmarkBcrypt11(b *testing.B){
benchmarkBcrypt(11, b)
}
func BenchmarkBcrypt12(b *testing.B){
benchmarkBcrypt(12, b)
}
func BenchmarkBcrypt13(b *testing.B){
benchmarkBcrypt(13, b)
}
func BenchmarkBcrypt14(b *testing.B){
benchmarkBcrypt(14, b)
}
Output:
BenchmarkBcrypt9-4 30 39543095 ns/op
BenchmarkBcrypt10-4 20 79184657 ns/op
BenchmarkBcrypt11-4 10 158688315 ns/op
BenchmarkBcrypt12-4 5 316070133 ns/op
BenchmarkBcrypt13-4 2 631838101 ns/op
BenchmarkBcrypt14-4 1 1275047344 ns/op
PASS
ok go-playground 10.670s
Old incorrect benchmark
I have a small set on benchmark test in golang and am curios of to what is a recommended bcrypt cost to use as of May 2018.
This is my benchrmark file:
package main
import "testing"
func BenchmarkBcrypt10(b *testing.B){
HashPassword("my pass", 10)
}
func BenchmarkBcrypt12(b *testing.B){
HashPassword("my pass", 12)
}
func BenchmarkBcrypt13(b *testing.B){
HashPassword("my pass", 13)
}
func BenchmarkBcrypt14(b *testing.B){
HashPassword("my pass", 14)
}
func BenchmarkBcrypt15(b *testing.B){
HashPassword("my pass", 15)
}
and this is HashPassword() func inside main.go:
import (
"golang.org/x/crypto/bcrypt"
)
func HashPassword(password string, cost int) (string, error) {
bytes, err := bcrypt.GenerateFromPassword(byte(password), cost)
return string(bytes), err
}
The current output is:
go test -bench=.
BenchmarkBcrypt10-4 2000000000 0.04 ns/op
BenchmarkBcrypt12-4 2000000000 0.16 ns/op
BenchmarkBcrypt13-4 2000000000 0.32 ns/op
BenchmarkBcrypt14-4 1 1281338532 ns/op
BenchmarkBcrypt15-4 1 2558998327 ns/op
PASS
It seems that for a bcrypt with cost of 13 the time it takes is 0.32 nanoseconds, and for cost 14 the time is 1281338532ns or ~1.2 seconds
Which I believe is too much. What do is the best bcrypt cost to use for the current year 2018.
go encryption hash bcrypt
1
10 is the default cost and your benchmarks is nonsensical (0.3ns/op means code compiled away by the compiler).
– Volker
May 22 '18 at 13:17
@Volker how can I benchmark time taken to execute the function?
– CommonSenseCode
May 22 '18 at 13:29
This is largely a matter of opinion and highly dependent upon what level of security is necessary for your particular application. Even NIST and OWASP, two of the top sources of security recommendations, remain intentionally vague on the subject of work factors.
– Adrian
May 22 '18 at 13:35
@commonSenseCode by not throwing away the result of the hash but e.g. keep it in a global.
– Volker
May 22 '18 at 13:54
@Volker I've been digging into this, and it doesn't feel like that's the problem. Even printing the hash doesn't change the result. I've also checked the error result, and it's fine, too. Even changing this toresult, _ = HashPassword(string(b.N), 10)generates the same timing. I'm wondering if it has to do with the calculation of N^work itself? (Though these times are really really short, so I'm not convinced that's it either.)
– Rob Napier
May 22 '18 at 14:01
|
show 3 more comments
Update
Actually it seems the benchmark was incorrectly setup I have followed the resource shared by user @Luke Joshua Park and now it works.
package main
import "testing"
func benchmarkBcrypt(i int, b *testing.B){
for n:= 0; n < b.N; n++ {
HashPassword("my pass", i)
}
}
func BenchmarkBcrypt9(b *testing.B){
benchmarkBcrypt(9, b)
}
func BenchmarkBcrypt10(b *testing.B){
benchmarkBcrypt(10, b)
}
func BenchmarkBcrypt11(b *testing.B){
benchmarkBcrypt(11, b)
}
func BenchmarkBcrypt12(b *testing.B){
benchmarkBcrypt(12, b)
}
func BenchmarkBcrypt13(b *testing.B){
benchmarkBcrypt(13, b)
}
func BenchmarkBcrypt14(b *testing.B){
benchmarkBcrypt(14, b)
}
Output:
BenchmarkBcrypt9-4 30 39543095 ns/op
BenchmarkBcrypt10-4 20 79184657 ns/op
BenchmarkBcrypt11-4 10 158688315 ns/op
BenchmarkBcrypt12-4 5 316070133 ns/op
BenchmarkBcrypt13-4 2 631838101 ns/op
BenchmarkBcrypt14-4 1 1275047344 ns/op
PASS
ok go-playground 10.670s
Old incorrect benchmark
I have a small set on benchmark test in golang and am curios of to what is a recommended bcrypt cost to use as of May 2018.
This is my benchrmark file:
package main
import "testing"
func BenchmarkBcrypt10(b *testing.B){
HashPassword("my pass", 10)
}
func BenchmarkBcrypt12(b *testing.B){
HashPassword("my pass", 12)
}
func BenchmarkBcrypt13(b *testing.B){
HashPassword("my pass", 13)
}
func BenchmarkBcrypt14(b *testing.B){
HashPassword("my pass", 14)
}
func BenchmarkBcrypt15(b *testing.B){
HashPassword("my pass", 15)
}
and this is HashPassword() func inside main.go:
import (
"golang.org/x/crypto/bcrypt"
)
func HashPassword(password string, cost int) (string, error) {
bytes, err := bcrypt.GenerateFromPassword(byte(password), cost)
return string(bytes), err
}
The current output is:
go test -bench=.
BenchmarkBcrypt10-4 2000000000 0.04 ns/op
BenchmarkBcrypt12-4 2000000000 0.16 ns/op
BenchmarkBcrypt13-4 2000000000 0.32 ns/op
BenchmarkBcrypt14-4 1 1281338532 ns/op
BenchmarkBcrypt15-4 1 2558998327 ns/op
PASS
It seems that for a bcrypt with cost of 13 the time it takes is 0.32 nanoseconds, and for cost 14 the time is 1281338532ns or ~1.2 seconds
Which I believe is too much. What do is the best bcrypt cost to use for the current year 2018.
go encryption hash bcrypt
Update
Actually it seems the benchmark was incorrectly setup I have followed the resource shared by user @Luke Joshua Park and now it works.
package main
import "testing"
func benchmarkBcrypt(i int, b *testing.B){
for n:= 0; n < b.N; n++ {
HashPassword("my pass", i)
}
}
func BenchmarkBcrypt9(b *testing.B){
benchmarkBcrypt(9, b)
}
func BenchmarkBcrypt10(b *testing.B){
benchmarkBcrypt(10, b)
}
func BenchmarkBcrypt11(b *testing.B){
benchmarkBcrypt(11, b)
}
func BenchmarkBcrypt12(b *testing.B){
benchmarkBcrypt(12, b)
}
func BenchmarkBcrypt13(b *testing.B){
benchmarkBcrypt(13, b)
}
func BenchmarkBcrypt14(b *testing.B){
benchmarkBcrypt(14, b)
}
Output:
BenchmarkBcrypt9-4 30 39543095 ns/op
BenchmarkBcrypt10-4 20 79184657 ns/op
BenchmarkBcrypt11-4 10 158688315 ns/op
BenchmarkBcrypt12-4 5 316070133 ns/op
BenchmarkBcrypt13-4 2 631838101 ns/op
BenchmarkBcrypt14-4 1 1275047344 ns/op
PASS
ok go-playground 10.670s
Old incorrect benchmark
I have a small set on benchmark test in golang and am curios of to what is a recommended bcrypt cost to use as of May 2018.
This is my benchrmark file:
package main
import "testing"
func BenchmarkBcrypt10(b *testing.B){
HashPassword("my pass", 10)
}
func BenchmarkBcrypt12(b *testing.B){
HashPassword("my pass", 12)
}
func BenchmarkBcrypt13(b *testing.B){
HashPassword("my pass", 13)
}
func BenchmarkBcrypt14(b *testing.B){
HashPassword("my pass", 14)
}
func BenchmarkBcrypt15(b *testing.B){
HashPassword("my pass", 15)
}
and this is HashPassword() func inside main.go:
import (
"golang.org/x/crypto/bcrypt"
)
func HashPassword(password string, cost int) (string, error) {
bytes, err := bcrypt.GenerateFromPassword(byte(password), cost)
return string(bytes), err
}
The current output is:
go test -bench=.
BenchmarkBcrypt10-4 2000000000 0.04 ns/op
BenchmarkBcrypt12-4 2000000000 0.16 ns/op
BenchmarkBcrypt13-4 2000000000 0.32 ns/op
BenchmarkBcrypt14-4 1 1281338532 ns/op
BenchmarkBcrypt15-4 1 2558998327 ns/op
PASS
It seems that for a bcrypt with cost of 13 the time it takes is 0.32 nanoseconds, and for cost 14 the time is 1281338532ns or ~1.2 seconds
Which I believe is too much. What do is the best bcrypt cost to use for the current year 2018.
go encryption hash bcrypt
go encryption hash bcrypt
edited May 25 '18 at 7:23
CommonSenseCode
asked May 22 '18 at 12:57
CommonSenseCodeCommonSenseCode
10k1678124
10k1678124
1
10 is the default cost and your benchmarks is nonsensical (0.3ns/op means code compiled away by the compiler).
– Volker
May 22 '18 at 13:17
@Volker how can I benchmark time taken to execute the function?
– CommonSenseCode
May 22 '18 at 13:29
This is largely a matter of opinion and highly dependent upon what level of security is necessary for your particular application. Even NIST and OWASP, two of the top sources of security recommendations, remain intentionally vague on the subject of work factors.
– Adrian
May 22 '18 at 13:35
@commonSenseCode by not throwing away the result of the hash but e.g. keep it in a global.
– Volker
May 22 '18 at 13:54
@Volker I've been digging into this, and it doesn't feel like that's the problem. Even printing the hash doesn't change the result. I've also checked the error result, and it's fine, too. Even changing this toresult, _ = HashPassword(string(b.N), 10)generates the same timing. I'm wondering if it has to do with the calculation of N^work itself? (Though these times are really really short, so I'm not convinced that's it either.)
– Rob Napier
May 22 '18 at 14:01
|
show 3 more comments
1
10 is the default cost and your benchmarks is nonsensical (0.3ns/op means code compiled away by the compiler).
– Volker
May 22 '18 at 13:17
@Volker how can I benchmark time taken to execute the function?
– CommonSenseCode
May 22 '18 at 13:29
This is largely a matter of opinion and highly dependent upon what level of security is necessary for your particular application. Even NIST and OWASP, two of the top sources of security recommendations, remain intentionally vague on the subject of work factors.
– Adrian
May 22 '18 at 13:35
@commonSenseCode by not throwing away the result of the hash but e.g. keep it in a global.
– Volker
May 22 '18 at 13:54
@Volker I've been digging into this, and it doesn't feel like that's the problem. Even printing the hash doesn't change the result. I've also checked the error result, and it's fine, too. Even changing this toresult, _ = HashPassword(string(b.N), 10)generates the same timing. I'm wondering if it has to do with the calculation of N^work itself? (Though these times are really really short, so I'm not convinced that's it either.)
– Rob Napier
May 22 '18 at 14:01
1
1
10 is the default cost and your benchmarks is nonsensical (0.3ns/op means code compiled away by the compiler).
– Volker
May 22 '18 at 13:17
10 is the default cost and your benchmarks is nonsensical (0.3ns/op means code compiled away by the compiler).
– Volker
May 22 '18 at 13:17
@Volker how can I benchmark time taken to execute the function?
– CommonSenseCode
May 22 '18 at 13:29
@Volker how can I benchmark time taken to execute the function?
– CommonSenseCode
May 22 '18 at 13:29
This is largely a matter of opinion and highly dependent upon what level of security is necessary for your particular application. Even NIST and OWASP, two of the top sources of security recommendations, remain intentionally vague on the subject of work factors.
– Adrian
May 22 '18 at 13:35
This is largely a matter of opinion and highly dependent upon what level of security is necessary for your particular application. Even NIST and OWASP, two of the top sources of security recommendations, remain intentionally vague on the subject of work factors.
– Adrian
May 22 '18 at 13:35
@commonSenseCode by not throwing away the result of the hash but e.g. keep it in a global.
– Volker
May 22 '18 at 13:54
@commonSenseCode by not throwing away the result of the hash but e.g. keep it in a global.
– Volker
May 22 '18 at 13:54
@Volker I've been digging into this, and it doesn't feel like that's the problem. Even printing the hash doesn't change the result. I've also checked the error result, and it's fine, too. Even changing this to
result, _ = HashPassword(string(b.N), 10) generates the same timing. I'm wondering if it has to do with the calculation of N^work itself? (Though these times are really really short, so I'm not convinced that's it either.)– Rob Napier
May 22 '18 at 14:01
@Volker I've been digging into this, and it doesn't feel like that's the problem. Even printing the hash doesn't change the result. I've also checked the error result, and it's fine, too. Even changing this to
result, _ = HashPassword(string(b.N), 10) generates the same timing. I'm wondering if it has to do with the calculation of N^work itself? (Though these times are really really short, so I'm not convinced that's it either.)– Rob Napier
May 22 '18 at 14:01
|
show 3 more comments
1 Answer
1
active
oldest
votes
I'm not certain what's going on with Benchmark here. If you just time these, it works fine, and you can work out the right answer for you.
package main
import (
"golang.org/x/crypto/bcrypt"
"time"
)
func main() {
cost := 10
start := time.Now()
bcrypt.GenerateFromPassword(byte("password"), cost)
end := time.Now()
print(end.Sub(start) / time.Millisecond)
}
For a work factor of 10, on my MacBook Pro I get 78ms. A work factor of 11 is 154ms, and 12 is 334ms. So we're seeing roughly doubling, as expected.
The goal is not a work factor; it's a time. You want as long as you can live with. In my experience (mostly working on client apps), 80-100ms is a nice target because compared to a network request it's undetectable to the user, while being massive in terms of brute-force attacks (so the default of 10 is ideal for my common use).
I generally avoid running password stretching on servers if I can help it, but this scale can be a reasonable trade-off between server impact and security. Remember that attackers may use something dramatically faster than a MacBook Pro, and may use multiple machines in parallel; I pick 80-100ms because of user experience trade-offs. (I perform password stretching on the client when I can get away with it, and then apply a cheap hash like SHA-256 on the server.)
But if you don't do this very often, or can spend more time on it, then longer is of course better, and on my MacBook Pro a work factor of 14 is about 1.2s, which I would certainly accept for some purposes.
But there's a reason that 10 is still the default. It's not an unreasonable value.
thanks rob I'll check this out later
– CommonSenseCode
May 22 '18 at 14:25
1
so better to just useDefaultCostvar from bcrypt package. Do you have an idea why the benchmarks don't work? when should one use benchmarks? I though it was a perfect use case for comparing bcrypt cost performances
– CommonSenseCode
May 24 '18 at 7:52
1
Just a tip, you can usetime.Since(start)instead oftime.Now().Sub(start)
– Moshe Revah
May 24 '18 at 18:19
2
The benchmark issue is due to the fact that you aren't running the codeb.Ntimes. This is required and not optional when writing Go benchmarks.
– Luke Joshua Park
May 24 '18 at 22:01
1
check my update the benchmark was incorrectly set, I used @Luke Josua Park resource and got it working. Do you think the output now makes sense it is roughly doubling with every increase of bcryp
– CommonSenseCode
May 25 '18 at 7:25
|
show 5 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f50468319%2fwhich-bcrypt-cost-to-use-for-2018%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I'm not certain what's going on with Benchmark here. If you just time these, it works fine, and you can work out the right answer for you.
package main
import (
"golang.org/x/crypto/bcrypt"
"time"
)
func main() {
cost := 10
start := time.Now()
bcrypt.GenerateFromPassword(byte("password"), cost)
end := time.Now()
print(end.Sub(start) / time.Millisecond)
}
For a work factor of 10, on my MacBook Pro I get 78ms. A work factor of 11 is 154ms, and 12 is 334ms. So we're seeing roughly doubling, as expected.
The goal is not a work factor; it's a time. You want as long as you can live with. In my experience (mostly working on client apps), 80-100ms is a nice target because compared to a network request it's undetectable to the user, while being massive in terms of brute-force attacks (so the default of 10 is ideal for my common use).
I generally avoid running password stretching on servers if I can help it, but this scale can be a reasonable trade-off between server impact and security. Remember that attackers may use something dramatically faster than a MacBook Pro, and may use multiple machines in parallel; I pick 80-100ms because of user experience trade-offs. (I perform password stretching on the client when I can get away with it, and then apply a cheap hash like SHA-256 on the server.)
But if you don't do this very often, or can spend more time on it, then longer is of course better, and on my MacBook Pro a work factor of 14 is about 1.2s, which I would certainly accept for some purposes.
But there's a reason that 10 is still the default. It's not an unreasonable value.
thanks rob I'll check this out later
– CommonSenseCode
May 22 '18 at 14:25
1
so better to just useDefaultCostvar from bcrypt package. Do you have an idea why the benchmarks don't work? when should one use benchmarks? I though it was a perfect use case for comparing bcrypt cost performances
– CommonSenseCode
May 24 '18 at 7:52
1
Just a tip, you can usetime.Since(start)instead oftime.Now().Sub(start)
– Moshe Revah
May 24 '18 at 18:19
2
The benchmark issue is due to the fact that you aren't running the codeb.Ntimes. This is required and not optional when writing Go benchmarks.
– Luke Joshua Park
May 24 '18 at 22:01
1
check my update the benchmark was incorrectly set, I used @Luke Josua Park resource and got it working. Do you think the output now makes sense it is roughly doubling with every increase of bcryp
– CommonSenseCode
May 25 '18 at 7:25
|
show 5 more comments
I'm not certain what's going on with Benchmark here. If you just time these, it works fine, and you can work out the right answer for you.
package main
import (
"golang.org/x/crypto/bcrypt"
"time"
)
func main() {
cost := 10
start := time.Now()
bcrypt.GenerateFromPassword(byte("password"), cost)
end := time.Now()
print(end.Sub(start) / time.Millisecond)
}
For a work factor of 10, on my MacBook Pro I get 78ms. A work factor of 11 is 154ms, and 12 is 334ms. So we're seeing roughly doubling, as expected.
The goal is not a work factor; it's a time. You want as long as you can live with. In my experience (mostly working on client apps), 80-100ms is a nice target because compared to a network request it's undetectable to the user, while being massive in terms of brute-force attacks (so the default of 10 is ideal for my common use).
I generally avoid running password stretching on servers if I can help it, but this scale can be a reasonable trade-off between server impact and security. Remember that attackers may use something dramatically faster than a MacBook Pro, and may use multiple machines in parallel; I pick 80-100ms because of user experience trade-offs. (I perform password stretching on the client when I can get away with it, and then apply a cheap hash like SHA-256 on the server.)
But if you don't do this very often, or can spend more time on it, then longer is of course better, and on my MacBook Pro a work factor of 14 is about 1.2s, which I would certainly accept for some purposes.
But there's a reason that 10 is still the default. It's not an unreasonable value.
thanks rob I'll check this out later
– CommonSenseCode
May 22 '18 at 14:25
1
so better to just useDefaultCostvar from bcrypt package. Do you have an idea why the benchmarks don't work? when should one use benchmarks? I though it was a perfect use case for comparing bcrypt cost performances
– CommonSenseCode
May 24 '18 at 7:52
1
Just a tip, you can usetime.Since(start)instead oftime.Now().Sub(start)
– Moshe Revah
May 24 '18 at 18:19
2
The benchmark issue is due to the fact that you aren't running the codeb.Ntimes. This is required and not optional when writing Go benchmarks.
– Luke Joshua Park
May 24 '18 at 22:01
1
check my update the benchmark was incorrectly set, I used @Luke Josua Park resource and got it working. Do you think the output now makes sense it is roughly doubling with every increase of bcryp
– CommonSenseCode
May 25 '18 at 7:25
|
show 5 more comments
I'm not certain what's going on with Benchmark here. If you just time these, it works fine, and you can work out the right answer for you.
package main
import (
"golang.org/x/crypto/bcrypt"
"time"
)
func main() {
cost := 10
start := time.Now()
bcrypt.GenerateFromPassword(byte("password"), cost)
end := time.Now()
print(end.Sub(start) / time.Millisecond)
}
For a work factor of 10, on my MacBook Pro I get 78ms. A work factor of 11 is 154ms, and 12 is 334ms. So we're seeing roughly doubling, as expected.
The goal is not a work factor; it's a time. You want as long as you can live with. In my experience (mostly working on client apps), 80-100ms is a nice target because compared to a network request it's undetectable to the user, while being massive in terms of brute-force attacks (so the default of 10 is ideal for my common use).
I generally avoid running password stretching on servers if I can help it, but this scale can be a reasonable trade-off between server impact and security. Remember that attackers may use something dramatically faster than a MacBook Pro, and may use multiple machines in parallel; I pick 80-100ms because of user experience trade-offs. (I perform password stretching on the client when I can get away with it, and then apply a cheap hash like SHA-256 on the server.)
But if you don't do this very often, or can spend more time on it, then longer is of course better, and on my MacBook Pro a work factor of 14 is about 1.2s, which I would certainly accept for some purposes.
But there's a reason that 10 is still the default. It's not an unreasonable value.
I'm not certain what's going on with Benchmark here. If you just time these, it works fine, and you can work out the right answer for you.
package main
import (
"golang.org/x/crypto/bcrypt"
"time"
)
func main() {
cost := 10
start := time.Now()
bcrypt.GenerateFromPassword(byte("password"), cost)
end := time.Now()
print(end.Sub(start) / time.Millisecond)
}
For a work factor of 10, on my MacBook Pro I get 78ms. A work factor of 11 is 154ms, and 12 is 334ms. So we're seeing roughly doubling, as expected.
The goal is not a work factor; it's a time. You want as long as you can live with. In my experience (mostly working on client apps), 80-100ms is a nice target because compared to a network request it's undetectable to the user, while being massive in terms of brute-force attacks (so the default of 10 is ideal for my common use).
I generally avoid running password stretching on servers if I can help it, but this scale can be a reasonable trade-off between server impact and security. Remember that attackers may use something dramatically faster than a MacBook Pro, and may use multiple machines in parallel; I pick 80-100ms because of user experience trade-offs. (I perform password stretching on the client when I can get away with it, and then apply a cheap hash like SHA-256 on the server.)
But if you don't do this very often, or can spend more time on it, then longer is of course better, and on my MacBook Pro a work factor of 14 is about 1.2s, which I would certainly accept for some purposes.
But there's a reason that 10 is still the default. It's not an unreasonable value.
edited Nov 25 '18 at 23:31
Alexis Wilke
10.2k34280
10.2k34280
answered May 22 '18 at 14:18
Rob NapierRob Napier
205k28303431
205k28303431
thanks rob I'll check this out later
– CommonSenseCode
May 22 '18 at 14:25
1
so better to just useDefaultCostvar from bcrypt package. Do you have an idea why the benchmarks don't work? when should one use benchmarks? I though it was a perfect use case for comparing bcrypt cost performances
– CommonSenseCode
May 24 '18 at 7:52
1
Just a tip, you can usetime.Since(start)instead oftime.Now().Sub(start)
– Moshe Revah
May 24 '18 at 18:19
2
The benchmark issue is due to the fact that you aren't running the codeb.Ntimes. This is required and not optional when writing Go benchmarks.
– Luke Joshua Park
May 24 '18 at 22:01
1
check my update the benchmark was incorrectly set, I used @Luke Josua Park resource and got it working. Do you think the output now makes sense it is roughly doubling with every increase of bcryp
– CommonSenseCode
May 25 '18 at 7:25
|
show 5 more comments
thanks rob I'll check this out later
– CommonSenseCode
May 22 '18 at 14:25
1
so better to just useDefaultCostvar from bcrypt package. Do you have an idea why the benchmarks don't work? when should one use benchmarks? I though it was a perfect use case for comparing bcrypt cost performances
– CommonSenseCode
May 24 '18 at 7:52
1
Just a tip, you can usetime.Since(start)instead oftime.Now().Sub(start)
– Moshe Revah
May 24 '18 at 18:19
2
The benchmark issue is due to the fact that you aren't running the codeb.Ntimes. This is required and not optional when writing Go benchmarks.
– Luke Joshua Park
May 24 '18 at 22:01
1
check my update the benchmark was incorrectly set, I used @Luke Josua Park resource and got it working. Do you think the output now makes sense it is roughly doubling with every increase of bcryp
– CommonSenseCode
May 25 '18 at 7:25
thanks rob I'll check this out later
– CommonSenseCode
May 22 '18 at 14:25
thanks rob I'll check this out later
– CommonSenseCode
May 22 '18 at 14:25
1
1
so better to just use
DefaultCost var from bcrypt package. Do you have an idea why the benchmarks don't work? when should one use benchmarks? I though it was a perfect use case for comparing bcrypt cost performances– CommonSenseCode
May 24 '18 at 7:52
so better to just use
DefaultCost var from bcrypt package. Do you have an idea why the benchmarks don't work? when should one use benchmarks? I though it was a perfect use case for comparing bcrypt cost performances– CommonSenseCode
May 24 '18 at 7:52
1
1
Just a tip, you can use
time.Since(start) instead of time.Now().Sub(start)– Moshe Revah
May 24 '18 at 18:19
Just a tip, you can use
time.Since(start) instead of time.Now().Sub(start)– Moshe Revah
May 24 '18 at 18:19
2
2
The benchmark issue is due to the fact that you aren't running the code
b.N times. This is required and not optional when writing Go benchmarks.– Luke Joshua Park
May 24 '18 at 22:01
The benchmark issue is due to the fact that you aren't running the code
b.N times. This is required and not optional when writing Go benchmarks.– Luke Joshua Park
May 24 '18 at 22:01
1
1
check my update the benchmark was incorrectly set, I used @Luke Josua Park resource and got it working. Do you think the output now makes sense it is roughly doubling with every increase of bcryp
– CommonSenseCode
May 25 '18 at 7:25
check my update the benchmark was incorrectly set, I used @Luke Josua Park resource and got it working. Do you think the output now makes sense it is roughly doubling with every increase of bcryp
– CommonSenseCode
May 25 '18 at 7:25
|
show 5 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f50468319%2fwhich-bcrypt-cost-to-use-for-2018%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
10 is the default cost and your benchmarks is nonsensical (0.3ns/op means code compiled away by the compiler).
– Volker
May 22 '18 at 13:17
@Volker how can I benchmark time taken to execute the function?
– CommonSenseCode
May 22 '18 at 13:29
This is largely a matter of opinion and highly dependent upon what level of security is necessary for your particular application. Even NIST and OWASP, two of the top sources of security recommendations, remain intentionally vague on the subject of work factors.
– Adrian
May 22 '18 at 13:35
@commonSenseCode by not throwing away the result of the hash but e.g. keep it in a global.
– Volker
May 22 '18 at 13:54
@Volker I've been digging into this, and it doesn't feel like that's the problem. Even printing the hash doesn't change the result. I've also checked the error result, and it's fine, too. Even changing this to
result, _ = HashPassword(string(b.N), 10)generates the same timing. I'm wondering if it has to do with the calculation of N^work itself? (Though these times are really really short, so I'm not convinced that's it either.)– Rob Napier
May 22 '18 at 14:01