Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
id
auth
Commits
613f57f8
Commit
613f57f8
authored
Dec 23, 2017
by
ale
Browse files
Use ai3/go-common for password hashing
parent
a430981a
Changes
24
Expand all
Hide whitespace changes
Inline
Side-by-side
server/authserver.go
View file @
613f57f8
...
...
@@ -9,13 +9,13 @@ import (
"path/filepath"
"strings"
scrypt
"github.com/elithrar/simple-scrypt"
"github.com/pquerna/otp/totp"
"github.com/prometheus/client_golang/prometheus"
"github.com/tstranex/u2f"
"gopkg.in/yaml.v2"
"git.autistici.org/ai3/go-common/clientutil"
"git.autistici.org/ai3/go-common/pwhash"
"git.autistici.org/id/auth"
)
...
...
@@ -561,8 +561,7 @@ func (s *Server) checkU2F(user *User, resp *u2f.SignResponse) bool {
}
func
checkPassword
(
password
,
hash
[]
byte
)
bool
{
err
:=
scrypt
.
CompareHashAndPassword
(
hash
,
password
)
return
err
==
nil
return
pwhash
.
ComparePassword
(
string
(
hash
),
string
(
password
))
}
func
checkOTP
(
otp
,
secret
string
)
bool
{
...
...
server/authserver_test.go
View file @
613f57f8
...
...
@@ -66,7 +66,7 @@ var (
testUsersFileStr
=
`---
- name: testuser
email: testuser@example.com
password: "16384$8$1$c479e8eb722f1b071efea7826ccf9c20$96d63ebed0c64afb746026f56f71b2a1f8796c73141d2d6b1958d4ea26c60a0b"
password: "
$s$
16384$8$1$c479e8eb722f1b071efea7826ccf9c20$96d63ebed0c64afb746026f56f71b2a1f8796c73141d2d6b1958d4ea26c60a0b"
groups:
- group1
- group2
...
...
@@ -74,7 +74,7 @@ var (
- name: 2fauser
email: 2fauser@example.com
shard: 42
password: "16384$8$1$c479e8eb722f1b071efea7826ccf9c20$96d63ebed0c64afb746026f56f71b2a1f8796c73141d2d6b1958d4ea26c60a0b"
password: "
$s$
16384$8$1$c479e8eb722f1b071efea7826ccf9c20$96d63ebed0c64afb746026f56f71b2a1f8796c73141d2d6b1958d4ea26c60a0b"
totp_secret: "O32OBVS5BL5EAPB5"
`
...
...
vendor/git.autistici.org/ai3/go-common/pwhash/password.go
0 → 100644
View file @
613f57f8
package
pwhash
import
(
"crypto/rand"
"crypto/subtle"
"encoding/hex"
"errors"
"fmt"
"io"
"strconv"
"strings"
"github.com/amoghe/go-crypt"
"golang.org/x/crypto/argon2"
"golang.org/x/crypto/scrypt"
)
// PasswordHash is a convenience interface common to all types in this package.
type
PasswordHash
interface
{
// ComparePassword returns true if the given password matches
// the encrypted one.
ComparePassword
(
string
,
string
)
bool
// Encrypt the given password.
Encrypt
(
string
)
string
}
// SystemCryptPasswordHash uses the glibc crypt function.
type
SystemCryptPasswordHash
struct
{}
// ComparePassword returns true if the given password matches the
// encrypted one.
func
(
s
*
SystemCryptPasswordHash
)
ComparePassword
(
encrypted
,
password
string
)
bool
{
enc2
,
err
:=
crypt
.
Crypt
(
password
,
encrypted
)
if
err
!=
nil
{
return
false
}
return
subtle
.
ConstantTimeCompare
([]
byte
(
encrypted
),
[]
byte
(
enc2
))
==
1
}
// Encrypt the given password using glibc crypt.
func
(
s
*
SystemCryptPasswordHash
)
Encrypt
(
password
string
)
string
{
salt
:=
fmt
.
Sprintf
(
"$6$%x$"
,
getRandomBytes
(
16
))
enc
,
err
:=
crypt
.
Crypt
(
password
,
salt
)
if
err
!=
nil
{
panic
(
err
)
}
return
enc
}
var
(
argonKeyLen
uint32
=
32
argonSaltLen
=
16
)
// Argon2PasswordHash uses the Argon2 hashing algorithm.
type
Argon2PasswordHash
struct
{}
// ComparePassword returns true if the given password matches the
// encrypted one.
func
(
s
*
Argon2PasswordHash
)
ComparePassword
(
encrypted
,
password
string
)
bool
{
params
,
salt
,
dk
,
err
:=
decodeArgon2Hash
(
encrypted
)
if
err
!=
nil
{
return
false
}
dk2
:=
argon2
.
Key
([]
byte
(
password
),
salt
,
params
.
Time
,
params
.
Memory
,
params
.
Threads
,
argonKeyLen
)
//log.Printf("params=%+v, salt=%+v, dk=%v, dk2=%v", params, salt, dk, dk2)
return
subtle
.
ConstantTimeCompare
(
dk
,
dk2
)
==
1
}
// Encrypt the given password with the Argon2 algorithm.
func
(
s
*
Argon2PasswordHash
)
Encrypt
(
password
string
)
string
{
salt
:=
getRandomBytes
(
argonSaltLen
)
params
:=
defaultArgon2Params
dk
:=
argon2
.
Key
([]
byte
(
password
),
salt
,
params
.
Time
,
params
.
Memory
,
params
.
Threads
,
argonKeyLen
)
return
encodeArgon2Hash
(
params
,
salt
,
dk
)
}
type
argon2Params
struct
{
Time
uint32
Memory
uint32
Threads
uint8
}
var
defaultArgon2Params
=
argon2Params
{
Time
:
4
,
Memory
:
32
*
1024
,
Threads
:
1
,
// Test fails with threads > 1 !!
//Threads: uint8(runtime.NumCPU()),
}
func
encodeArgon2Hash
(
params
argon2Params
,
salt
,
dk
[]
byte
)
string
{
return
fmt
.
Sprintf
(
"$a2$%d$%d$%d$%x$%x"
,
params
.
Time
,
params
.
Memory
,
params
.
Threads
,
salt
,
dk
)
}
func
decodeArgon2Hash
(
s
string
)
(
params
argon2Params
,
salt
[]
byte
,
dk
[]
byte
,
err
error
)
{
if
!
strings
.
HasPrefix
(
s
,
"$a2$"
)
{
err
=
errors
.
New
(
"not an Argon2 password hash"
)
return
}
parts
:=
strings
.
SplitN
(
s
[
4
:
],
"$"
,
5
)
if
len
(
parts
)
!=
5
{
err
=
errors
.
New
(
"bad encoding"
)
return
}
var
i
uint64
if
i
,
err
=
strconv
.
ParseUint
(
parts
[
0
],
10
,
32
);
err
!=
nil
{
return
}
params
.
Time
=
uint32
(
i
)
if
i
,
err
=
strconv
.
ParseUint
(
parts
[
1
],
10
,
32
);
err
!=
nil
{
return
}
params
.
Memory
=
uint32
(
i
)
if
i
,
err
=
strconv
.
ParseUint
(
parts
[
2
],
10
,
8
);
err
!=
nil
{
return
}
params
.
Threads
=
uint8
(
i
)
if
salt
,
err
=
hex
.
DecodeString
(
parts
[
3
]);
err
!=
nil
{
return
}
dk
,
err
=
hex
.
DecodeString
(
parts
[
4
])
return
}
var
(
scryptKeyLen
=
32
scryptSaltLen
=
16
)
// ScryptPasswordHash uses the scrypt hashing algorithm.
type
ScryptPasswordHash
struct
{}
// ComparePassword returns true if the given password matches
// the encrypted one.
func
(
s
*
ScryptPasswordHash
)
ComparePassword
(
encrypted
,
password
string
)
bool
{
params
,
salt
,
dk
,
err
:=
decodeScryptHash
(
encrypted
)
if
err
!=
nil
{
return
false
}
dk2
,
err
:=
scrypt
.
Key
([]
byte
(
password
),
salt
,
params
.
N
,
params
.
R
,
params
.
P
,
scryptKeyLen
)
if
err
!=
nil
{
return
false
}
//log.Printf("params=%+v, salt=%+v, dk=%v, dk2=%v", params, salt, dk, dk2)
return
subtle
.
ConstantTimeCompare
(
dk
,
dk2
)
==
1
}
// Encrypt the given password with the scrypt algorithm.
func
(
s
*
ScryptPasswordHash
)
Encrypt
(
password
string
)
string
{
salt
:=
getRandomBytes
(
scryptSaltLen
)
params
:=
defaultScryptParams
dk
,
err
:=
scrypt
.
Key
([]
byte
(
password
),
salt
,
params
.
N
,
params
.
R
,
params
.
P
,
scryptKeyLen
)
if
err
!=
nil
{
panic
(
err
)
}
return
encodeScryptHash
(
params
,
salt
,
dk
)
}
type
scryptParams
struct
{
N
int
R
int
P
int
}
var
defaultScryptParams
=
scryptParams
{
N
:
16384
,
R
:
8
,
P
:
1
,
}
func
encodeScryptHash
(
params
scryptParams
,
salt
,
dk
[]
byte
)
string
{
return
fmt
.
Sprintf
(
"$s$%d$%d$%d$%x$%x"
,
params
.
N
,
params
.
R
,
params
.
P
,
salt
,
dk
)
}
func
decodeScryptHash
(
s
string
)
(
params
scryptParams
,
salt
[]
byte
,
dk
[]
byte
,
err
error
)
{
if
!
strings
.
HasPrefix
(
s
,
"$s$"
)
{
err
=
errors
.
New
(
"not a scrypt password hash"
)
return
}
parts
:=
strings
.
SplitN
(
s
[
3
:
],
"$"
,
5
)
if
len
(
parts
)
!=
5
{
err
=
errors
.
New
(
"bad encoding"
)
return
}
if
params
.
N
,
err
=
strconv
.
Atoi
(
parts
[
0
]);
err
!=
nil
{
return
}
if
params
.
R
,
err
=
strconv
.
Atoi
(
parts
[
1
]);
err
!=
nil
{
return
}
if
params
.
P
,
err
=
strconv
.
Atoi
(
parts
[
2
]);
err
!=
nil
{
return
}
if
salt
,
err
=
hex
.
DecodeString
(
parts
[
3
]);
err
!=
nil
{
return
}
dk
,
err
=
hex
.
DecodeString
(
parts
[
4
])
return
}
func
getRandomBytes
(
n
int
)
[]
byte
{
b
:=
make
([]
byte
,
n
)
_
,
err
:=
io
.
ReadFull
(
rand
.
Reader
,
b
[
:
])
if
err
!=
nil
{
panic
(
err
)
}
return
b
}
var
prefixRegistry
=
map
[
string
]
PasswordHash
{
"$1$"
:
&
SystemCryptPasswordHash
{},
"$5$"
:
&
SystemCryptPasswordHash
{},
"$6$"
:
&
SystemCryptPasswordHash
{},
"$s$"
:
&
ScryptPasswordHash
{},
"$a2$"
:
&
Argon2PasswordHash
{},
}
// ComparePassword returns true if the given password matches the
// encrypted one.
func
ComparePassword
(
encrypted
,
password
string
)
bool
{
for
pfx
,
h
:=
range
prefixRegistry
{
if
strings
.
HasPrefix
(
encrypted
,
pfx
)
{
return
h
.
ComparePassword
(
encrypted
,
password
)
}
}
return
false
}
// DefaultEncryptAlgorithm is used by the Encrypt function to encrypt
// passwords.
var
DefaultEncryptAlgorithm
PasswordHash
=
&
Argon2PasswordHash
{}
// Encrypt will encrypt a password with the default algorithm.
func
Encrypt
(
password
string
)
string
{
return
DefaultEncryptAlgorithm
.
Encrypt
(
password
)
}
vendor/github.com/amoghe/go-crypt/LICENSE
0 → 100644
View file @
613f57f8
The MIT License (MIT)
Copyright (c) 2015 Akshay Moghe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
vendor/github.com/amoghe/go-crypt/README.md
0 → 100644
View file @
613f57f8
go-crypt (`crypt`)
==================
[

](https://travis-ci.org/amoghe/go-crypt)
Package
`crypt`
provides go language wrappers around crypt(3). For further information on crypt see the
[
man page
](
http://man7.org/linux/man-pages/man3/crypt.3.html
)
If you have questions about how to use crypt (the C function), it is likely this is not the package you
are looking for.
**NOTE**
Depending on the platform, this package provides a
`Crypt`
function that is backed by different
flavors of the libc crypt. This is done by detecting the GOOS and trying to build using
`crypt_r`
(the GNU
extension) when on linux, and wrapping around plain 'ol
`crypt`
(guarded by a global lock) otherwise.
Example
-------
```
go
import
(
"fmt"
"github.com/amoghe/go-crypt"
)
func
main
()
{
md5
,
err
:=
crypt
.
Crypt
(
"password"
,
"in"
)
if
err
!=
nil
{
fmt
.
Errorf
(
"error:"
,
err
)
return
}
sha512
,
err
:=
crypt
.
Crypt
(
"password"
,
"$6$SomeSaltSomePepper$"
)
if
err
!=
nil
{
fmt
.
Errorf
(
"error:"
,
err
)
return
}
fmt
.
Println
(
"MD5:"
,
md5
)
fmt
.
Println
(
"SHA512:"
,
sha512
)
}
```
A Note On "Salt"
----------------
You can find out more about salt
[
here
](
https://en.wikipedia.org/wiki/Salt_(cryptography
)
)
The hash algorithm can be selected via the salt string. Here is how to do it (relevant
section from the man page):
```
If salt is a character string starting with the characters
"$id$" followed by a string terminated by "$":
$id$salt$encrypted
then instead of using the DES machine, id identifies the
encryption method used and this then determines how the rest
of the password string is interpreted. The following values
of id are supported:
ID | Method
─────────────────────────────────────────────────────────
1 | MD5
2a | Blowfish (not in mainline glibc; added in some
| Linux distributions)
5 | SHA-256 (since glibc 2.7)
6 | SHA-512 (since glibc 2.7)
So $5$salt$encrypted is an SHA-256 encoded password and
$6$salt$encrypted is an SHA-512 encoded one.
"salt" stands for the up to 16 characters following "$id$" in
the salt. The encrypted part of the password string is the
actual computed password. The size of this string is fixed:
MD5 | 22 characters
SHA-256 | 43 characters
SHA-512 | 86 characters
```
Platforms
---------
This package has been tested on the following platforms:
-
ubuntu 14.04.2 (libc 2.19)
-
ubuntu 12.04.5 (libc 2.15)
-
centos (libc 2.17)
-
fedora 22 (libc 2.21)
All the platforms tested on have GNU libc (with extensions) so that the GOOS=linux always
compiles the reentrant versions of the crypt function (
`crypt_r`
), and exposes it to go land.
Other platforms (freebsd, netbsd) should also work (in theory) since their libc expose at least
a posix compliant crypt function. On these platforms the fallback should compile and expose the
'plain' (non reentrant, thus globally locked) crypt function.
Unfortunately, I do not have access to machines that run anything other than Linux, hence the other
platforms have not been tested, however I believe they should work just fine. If you can verify this
(or provide a patch that fixes this), I would be grateful.
TODO
----
*
Find someone with access to
*
BSD system(s)
License
-------
Released under the
[
MIT License
](
LICENSE
)
vendor/github.com/amoghe/go-crypt/crypt.go
0 → 100644
View file @
613f57f8
// +build darwin freebsd netbsd
// Package crypt provides wrappers around functions available in crypt.h
//
// It wraps around the GNU specific extension (crypt) when the reentrant version
// (crypt_r) is unavailable. The non-reentrant version is guarded by a global lock
// so as to be safely callable from concurrent goroutines.
package
crypt
import
(
"sync"
"unsafe"
)
/*
#define _GNU_SOURCE
#include <unistd.h>
*/
import
"C"
var
(
mu
sync
.
Mutex
)
// Crypt provides a wrapper around the glibc crypt() function.
// For the meaning of the arguments, refer to the README.
func
Crypt
(
pass
,
salt
string
)
(
string
,
error
)
{
c_pass
:=
C
.
CString
(
pass
)
defer
C
.
free
(
unsafe
.
Pointer
(
c_pass
))
c_salt
:=
C
.
CString
(
salt
)
defer
C
.
free
(
unsafe
.
Pointer
(
c_salt
))
mu
.
Lock
()
c_enc
,
err
:=
C
.
crypt
(
c_pass
,
c_salt
)
mu
.
Unlock
()
if
c_enc
==
nil
{
return
""
,
err
}
defer
C
.
free
(
unsafe
.
Pointer
(
c_enc
))
// Return nil error if the string is non-nil.
// As per the errno.h manpage, functions are allowed to set errno
// on success. Caller should ignore errno on success.
return
C
.
GoString
(
c_enc
),
err
}
vendor/github.com/amoghe/go-crypt/crypt_r.go
0 → 100644
View file @
613f57f8
// +build linux
// Package crypt provides wrappers around functions available in crypt.h
//
// It wraps around the GNU specific extension (crypt_r) when it is available
// (i.e. where GOOS=linux). This makes the go function reentrant (and thus
// callable from concurrent goroutines).
package
crypt
import
(
"unsafe"
)
/*
#cgo LDFLAGS: -lcrypt
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <crypt.h>
char *gnu_ext_crypt(char *pass, char *salt) {
char *enc = NULL;
char *ret = NULL;
struct crypt_data data;
data.initialized = 0;
enc = crypt_r(pass, salt, &data);
if(enc == NULL) {
return NULL;
}
ret = (char *)malloc(strlen(enc)+1); // for trailing null
strncpy(ret, enc, strlen(enc));
ret[strlen(enc)]= '\0'; // paranoid
return ret;
}
*/
import
"C"
// Crypt provides a wrapper around the glibc crypt_r() function.
// For the meaning of the arguments, refer to the package README.
func
Crypt
(
pass
,
salt
string
)
(
string
,
error
)
{
c_pass
:=
C
.
CString
(
pass
)
defer
C
.
free
(
unsafe
.
Pointer
(
c_pass
))
c_salt
:=
C
.
CString
(
salt
)
defer
C
.
free
(
unsafe
.
Pointer
(
c_salt
))
c_enc
,
err
:=
C
.
gnu_ext_crypt
(
c_pass
,
c_salt
)
if
c_enc
==
nil
{
return
""
,
err
}
defer
C
.
free
(
unsafe
.
Pointer
(
c_enc
))
// Return nil error if the string is non-nil.
// As per the errno.h manpage, functions are allowed to set errno
// on success. Caller should ignore errno on success.
return
C
.
GoString
(
c_enc
),
nil
}
vendor/github.com/amoghe/go-crypt/version.go
0 → 100644
View file @
613f57f8
package
crypt
/*
#include <gnu/libc-version.h>
*/
import
"C"
// Returns version string from libc
func
LibCVersion
()
string
{
c_ver
:=
C
.
gnu_get_libc_version
()
return
C
.
GoString
(
c_ver
)
}
vendor/golang.org/x/crypto/argon2/argon2.go
0 → 100644
View file @
613f57f8
// Copyright 2017 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 argon2 implements the key derivation function Argon2.
// Argon2 was selected as the winner of the Password Hashing Competition and can
// be used to derive cryptographic keys from passwords.
// Argon2 is specfifed at https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
package
argon2
import
(
"encoding/binary"
"sync"
"golang.org/x/crypto/blake2b"
)
// The Argon2 version implemented by this package.
const
Version
=
0x13
const
(
argon2d
=
iota
argon2i
argon2id
)
// Key derives a key from the password, salt, and cost parameters using Argon2i
// returning a byte slice of length keyLen that can be used as cryptographic key.
// The CPU cost and parallism degree must be greater than zero.
//
// For example, you can get a derived key for e.g. AES-256 (which needs a 32-byte key) by doing:
// `key := argon2.Key([]byte("some password"), salt, 4, 32*1024, 4, 32)`
//
// The recommended parameters for interactive logins as of 2017 are time=4, memory=32*1024.
// The number of threads can be adjusted to the numbers of available CPUs.
// The time parameter specifies the number of passes over the memory and the memory
// parameter specifies the size of the memory in KiB. For example memory=32*1024 sets the
// memory cost to ~32 MB.
// The cost parameters should be increased as memory latency and CPU parallelism increases.
// Remember to get a good random salt.
func
Key
(
password
,
salt
[]
byte
,
time
,
memory
uint32
,
threads
uint8
,
keyLen
uint32
)
[]
byte
{
return
deriveKey
(
argon2i
,
password
,
salt
,
nil
,
nil
,
time
,
memory
,
threads
,
keyLen
)
}
func
deriveKey
(
mode
int
,
password
,
salt
,
secret
,
data
[]
byte
,
time
,
memory
uint32
,
threads
uint8
,
keyLen
uint32
)
[]
byte
{
if
time
<
1
{
panic
(
"argon2: number of rounds too small"
)
}
if
threads
<
1
{
panic
(
"argon2: paralisim degree too low"
)
}
mem
:=
memory
/
(
4
*
uint32
(
threads
))
*
(
4
*
uint32
(
threads
))
if
mem
<
8
*
uint32
(
threads
)
{