]> Cypherpunks.ru repositories - gocheese.git/blob - argon2i.go
Add auth with argon2i and sha256 hashed passwords
[gocheese.git] / argon2i.go
1 /*
2 GoCheese -- Python private package repository and caching proxy
3 Copyright (C) 2019 Elena Balakhonova <balakhonova_e@riseup.net>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 // Python private package repository and caching proxy
19 package main
20
21 import (
22         "bytes"
23         "encoding/base64"
24         "errors"
25         "fmt"
26         "strings"
27
28         "golang.org/x/crypto/argon2"
29 )
30
31 type Argon2iAuthData struct {
32         version  int
33         memory   uint32
34         time     uint32
35         threads  uint8
36         salt     []byte
37         password []byte
38 }
39
40 func (ad Argon2iAuthData) Auth(password string) bool {
41         hashedPassword := argon2.Key(
42                 []byte(password),
43                 ad.salt,
44                 ad.time,
45                 ad.memory,
46                 ad.threads,
47                 uint32(len(ad.password)),
48         )
49         return bytes.Equal(hashedPassword, ad.password)
50 }
51
52 func parseArgon2i(params string) (Auther, error) {
53         var time, memory uint32
54         var threads uint8
55         var version int
56         var saltAndPasswordUnitedB64 string
57         n, err := fmt.Sscanf(
58                 params,
59                 "v=%d$m=%d,t=%d,p=%d$%s",
60                 &version,
61                 &memory,
62                 &time,
63                 &threads,
64                 &saltAndPasswordUnitedB64,
65         )
66         if n != 5 || err != nil {
67                 return nil, fmt.Errorf("argon2i parameters %q have wrong format", params)
68         }
69         if version != argon2.Version {
70                 return nil, errors.New("unsupported argon2i version")
71         }
72         saltAndPasswordSplittedB64 := strings.Split(saltAndPasswordUnitedB64, "$")
73         salt, err := base64.RawStdEncoding.DecodeString(saltAndPasswordSplittedB64[0])
74         if err != nil {
75                 return nil, errors.New("invalid salt format")
76         }
77         password, err := base64.RawStdEncoding.DecodeString(saltAndPasswordSplittedB64[1])
78         if err != nil {
79                 return nil, errors.New("invalid password format")
80         }
81         return Argon2iAuthData{
82                 version:  version,
83                 time:     time,
84                 memory:   memory,
85                 threads:  threads,
86                 salt:     salt,
87                 password: password,
88         }, nil
89 }