mirror of
https://github.com/Luzifer/cloudkeys-go.git
synced 2024-11-10 07:00:08 +00:00
Knut Ahlers
a1df72edc5
commitf0db1ff1f8
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:19:56 2017 +0100 Mark option as deprecated Signed-off-by: Knut Ahlers <knut@ahlers.me> commit9891df2a16
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:11:56 2017 +0100 Fix: Typo Signed-off-by: Knut Ahlers <knut@ahlers.me> commit836006de64
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:04:20 2017 +0100 Add new dependencies Signed-off-by: Knut Ahlers <knut@ahlers.me> commitd64fee60c8
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 11:55:52 2017 +0100 Replace insecure password hashing Prior this commit passwords were hashed with a static salt and using the SHA1 hashing function. This could lead to passwords being attackable in case someone gets access to the raw data stored inside the database. This commit introduces password hashing using bcrypt hashing function which addresses this issue. Old passwords are not automatically re-hashed as they are unknown. Replacing the old password scheme is not that easy and needs #10 to be solved. Therefore the old hashing scheme is kept for compatibility reason. Signed-off-by: Knut Ahlers <knut@ahlers.me> Signed-off-by: Knut Ahlers <knut@ahlers.me> closes #14 closes #15
170 lines
5.5 KiB
Go
170 lines
5.5 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package pkcs12
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha1"
|
|
"math/big"
|
|
)
|
|
|
|
var (
|
|
one = big.NewInt(1)
|
|
)
|
|
|
|
// sha1Sum returns the SHA-1 hash of in.
|
|
func sha1Sum(in []byte) []byte {
|
|
sum := sha1.Sum(in)
|
|
return sum[:]
|
|
}
|
|
|
|
// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of
|
|
// repeats of pattern.
|
|
func fillWithRepeats(pattern []byte, v int) []byte {
|
|
if len(pattern) == 0 {
|
|
return nil
|
|
}
|
|
outputLen := v * ((len(pattern) + v - 1) / v)
|
|
return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen]
|
|
}
|
|
|
|
func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
|
|
// implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments
|
|
|
|
// Let H be a hash function built around a compression function f:
|
|
|
|
// Z_2^u x Z_2^v -> Z_2^u
|
|
|
|
// (that is, H has a chaining variable and output of length u bits, and
|
|
// the message input to the compression function of H is v bits). The
|
|
// values for u and v are as follows:
|
|
|
|
// HASH FUNCTION VALUE u VALUE v
|
|
// MD2, MD5 128 512
|
|
// SHA-1 160 512
|
|
// SHA-224 224 512
|
|
// SHA-256 256 512
|
|
// SHA-384 384 1024
|
|
// SHA-512 512 1024
|
|
// SHA-512/224 224 1024
|
|
// SHA-512/256 256 1024
|
|
|
|
// Furthermore, let r be the iteration count.
|
|
|
|
// We assume here that u and v are both multiples of 8, as are the
|
|
// lengths of the password and salt strings (which we denote by p and s,
|
|
// respectively) and the number n of pseudorandom bits required. In
|
|
// addition, u and v are of course non-zero.
|
|
|
|
// For information on security considerations for MD5 [19], see [25] and
|
|
// [1], and on those for MD2, see [18].
|
|
|
|
// The following procedure can be used to produce pseudorandom bits for
|
|
// a particular "purpose" that is identified by a byte called "ID".
|
|
// This standard specifies 3 different values for the ID byte:
|
|
|
|
// 1. If ID=1, then the pseudorandom bits being produced are to be used
|
|
// as key material for performing encryption or decryption.
|
|
|
|
// 2. If ID=2, then the pseudorandom bits being produced are to be used
|
|
// as an IV (Initial Value) for encryption or decryption.
|
|
|
|
// 3. If ID=3, then the pseudorandom bits being produced are to be used
|
|
// as an integrity key for MACing.
|
|
|
|
// 1. Construct a string, D (the "diversifier"), by concatenating v/8
|
|
// copies of ID.
|
|
var D []byte
|
|
for i := 0; i < v; i++ {
|
|
D = append(D, ID)
|
|
}
|
|
|
|
// 2. Concatenate copies of the salt together to create a string S of
|
|
// length v(ceiling(s/v)) bits (the final copy of the salt may be
|
|
// truncated to create S). Note that if the salt is the empty
|
|
// string, then so is S.
|
|
|
|
S := fillWithRepeats(salt, v)
|
|
|
|
// 3. Concatenate copies of the password together to create a string P
|
|
// of length v(ceiling(p/v)) bits (the final copy of the password
|
|
// may be truncated to create P). Note that if the password is the
|
|
// empty string, then so is P.
|
|
|
|
P := fillWithRepeats(password, v)
|
|
|
|
// 4. Set I=S||P to be the concatenation of S and P.
|
|
I := append(S, P...)
|
|
|
|
// 5. Set c=ceiling(n/u).
|
|
c := (size + u - 1) / u
|
|
|
|
// 6. For i=1, 2, ..., c, do the following:
|
|
A := make([]byte, c*20)
|
|
var IjBuf []byte
|
|
for i := 0; i < c; i++ {
|
|
// A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
|
|
// H(H(H(... H(D||I))))
|
|
Ai := hash(append(D, I...))
|
|
for j := 1; j < r; j++ {
|
|
Ai = hash(Ai)
|
|
}
|
|
copy(A[i*20:], Ai[:])
|
|
|
|
if i < c-1 { // skip on last iteration
|
|
// B. Concatenate copies of Ai to create a string B of length v
|
|
// bits (the final copy of Ai may be truncated to create B).
|
|
var B []byte
|
|
for len(B) < v {
|
|
B = append(B, Ai[:]...)
|
|
}
|
|
B = B[:v]
|
|
|
|
// C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
|
|
// blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
|
|
// setting I_j=(I_j+B+1) mod 2^v for each j.
|
|
{
|
|
Bbi := new(big.Int).SetBytes(B)
|
|
Ij := new(big.Int)
|
|
|
|
for j := 0; j < len(I)/v; j++ {
|
|
Ij.SetBytes(I[j*v : (j+1)*v])
|
|
Ij.Add(Ij, Bbi)
|
|
Ij.Add(Ij, one)
|
|
Ijb := Ij.Bytes()
|
|
// We expect Ijb to be exactly v bytes,
|
|
// if it is longer or shorter we must
|
|
// adjust it accordingly.
|
|
if len(Ijb) > v {
|
|
Ijb = Ijb[len(Ijb)-v:]
|
|
}
|
|
if len(Ijb) < v {
|
|
if IjBuf == nil {
|
|
IjBuf = make([]byte, v)
|
|
}
|
|
bytesShort := v - len(Ijb)
|
|
for i := 0; i < bytesShort; i++ {
|
|
IjBuf[i] = 0
|
|
}
|
|
copy(IjBuf[bytesShort:], Ijb)
|
|
Ijb = IjBuf
|
|
}
|
|
copy(I[j*v:(j+1)*v], Ijb)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
|
|
// bit string, A.
|
|
|
|
// 8. Use the first n bits of A as the output of this entire process.
|
|
return A[:size]
|
|
|
|
// If the above process is being used to generate a DES key, the process
|
|
// should be used to create 64 random bits, and the key's parity bits
|
|
// should be set after the 64 bits have been produced. Similar concerns
|
|
// hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any
|
|
// similar keys with parity bits "built into them".
|
|
}
|