58 lines
1.6 KiB
Go
58 lines
1.6 KiB
Go
package ficha
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"strings"
|
|
)
|
|
|
|
const tokenVersion = "v1"
|
|
|
|
// encodeToken builds the wire format: v1.<keyID>.<base64url(none||ciphertext)>
|
|
func encodeToken(keyID string, nonce, ciphertext []byte) string {
|
|
body := make([]byte, 0, len(nonce)+len(ciphertext))
|
|
body = append(body, nonce...)
|
|
body = append(body, ciphertext...)
|
|
|
|
var b strings.Builder
|
|
b.Grow(len(tokenVersion) + 1 + len(keyID) + 1 + base64.RawURLEncoding.EncodedLen(len(body)))
|
|
b.WriteString(tokenVersion)
|
|
b.WriteByte('.')
|
|
b.WriteString(keyID)
|
|
b.WriteByte('.')
|
|
b.WriteString(base64.RawURLEncoding.EncodeToString(body))
|
|
|
|
return b.String()
|
|
}
|
|
|
|
// decodeToken parses the wire format and splits the body back into nonce and ciphertext.
|
|
// Returns ErrInvalidToken for any malformed input.
|
|
func decodeToken(token string) (keyID string, nonce, ciphertext []byte, err error) {
|
|
parts := strings.SplitN(token, ".", 3)
|
|
if len(parts) != 3 {
|
|
return "", nil, nil, ErrInvalidToken
|
|
}
|
|
if parts[0] != tokenVersion {
|
|
return "", nil, nil, ErrInvalidToken
|
|
}
|
|
if parts[1] == "" {
|
|
return "", nil, nil, ErrInvalidToken
|
|
}
|
|
|
|
body, err := base64.RawURLEncoding.DecodeString(parts[2])
|
|
if err != nil {
|
|
return "", nil, nil, ErrInvalidToken
|
|
}
|
|
|
|
// body must be at least nonce + auth tag (16 bytes)
|
|
if len(body) < nonceSize+16 {
|
|
return "", nil, nil, ErrInvalidToken
|
|
}
|
|
|
|
return parts[1], body[:nonceSize], body[nonceSize:], nil
|
|
}
|
|
|
|
// aadFor builds the AAD bytes for a given version+keyID. Both encrypt
|
|
// and decrypt must use the same construction.
|
|
func aadFor(keyID string) []byte {
|
|
return []byte(tokenVersion + "." + keyID)
|
|
}
|