package crypt
import (
)
type crypterArgon2 struct {
rand io.Reader
}
func ( *crypterArgon2) ( string, phcformat.Hash) (string, error) {
if , := .Version.Unwrap(); {
, := strconv.ParseUint(, 10, 32)
if != nil {
return "", fmt.Errorf("parse version: %w", )
}
if != argon2.Version {
return "", &crypterrors.UnsupportedVersionError{
Parsed: uint(),
Suggested: argon2.Version,
}
}
}
var , uint32
var uint8
:= phcformat.IterParams(option.UnwrapOrZero(.Params))
for ; .Valid; = .Next() {
:= "[1;math.MaxUint32]"
var uint64
var bool
var error
switch .Name {
case "m":
, = strconv.ParseUint(.Value, 10, 32)
= uint32()
case "t":
, = strconv.ParseUint(.Value, 10, 32)
= uint32()
case "p":
, = strconv.ParseUint(.Value, 10, 8)
= uint8()
= "[1;math.MaxUint8]"
case "keyid", "data":
= true
fallthrough
default:
return "", &crypterrors.UnsupportedParameterError{
Name: .Name,
Unimplemented: ,
}
}
if != nil {
return "", fmt.Errorf("parse parameter %q: %w", .Name, )
}
if < 1 {
return "", &crypterrors.InvalidParameterValueError{
Name: .Name,
Value: .Value,
Expected: ,
}
}
}
if .After != "" {
return "", &crypterrors.MalformedParametersError{
Unparsed: .After,
}
}
if == 0 || == 0 || == 0 {
return "", &crypterrors.MissingRequiredParametersError{
Required: "m, t, p",
}
}
var []byte
if , := .Salt.Unwrap(); {
var error
, = b64.DecodeString()
if != nil {
return "", fmt.Errorf("decode salt: %w", )
}
} else {
= make([]byte, 32)
, := io.ReadFull(.rand, )
if != nil {
return "", fmt.Errorf("generate salt: %w", )
}
}
:= uint32(32)
if , := .Output.Unwrap(); {
:= b64.DecodedLen(len())
if <= 0 || > math.MaxUint32 {
return "", &crypterrors.InvalidOutputLengthError{
Length: ,
Expected: "non-zero unsigned 32-bit integer",
}
}
= uint32()
}
var []byte
if .ID == schemeArgon2id {
= argon2.IDKey([]byte(), , , , , )
} else {
= argon2.Key([]byte(), , , , , )
}
:= len(.Raw)
if option.IsNil(.Salt) {
+= 1 + b64.EncodedLen(len())
}
if , := .Output.Unwrap(); {
-= 1 + len()
}
+= 1 + b64.EncodedLen(len())
return string(phcformat.Append(make([]byte, 0, ),
encode.NewString(.ID),
option.Map(.Version, encode.NewString),
option.Map(.Params, encode.NewString),
option.Value(encode.NewBase64()),
option.Value(encode.NewBase64()),
)), nil
}