Separate the window sentence from the wrapped error so a bad certificate file is not reported as a key mismatch.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-07 15:01:38 +02:00
co-authored by Cursor
parent a405048f23
commit e642b24be0
17 changed files with 842 additions and 742 deletions
+4 -56
View File
@@ -1,11 +1,9 @@
package station
import (
"crypto/aes"
"crypto/cipher"
"crypto/subtle"
"encoding/binary"
"errors"
"gitea.neitzel.de/konrad/funknetz/internal/gcm64"
)
func counterAAD(counter uint32) []byte {
@@ -19,16 +17,8 @@ func registrationAAD(clientID uint16) []byte {
return appendU16(b, clientID)
}
func ivFor(prefix []byte, clientID uint16, counter uint32) []byte {
iv := make([]byte, 12)
copy(iv, prefix)
binary.BigEndian.PutUint16(iv[6:8], clientID)
binary.BigEndian.PutUint32(iv[8:12], counter)
return iv
}
func sealDatagram(key, prefix []byte, clientID uint16, counter uint32, aad, plain []byte) ([]byte, error) {
tag, ct, err := sealTrunc(key, ivFor(prefix, clientID, counter), plain, aad)
tag, ct, err := gcm64.Seal(key, gcm64.IV(prefix, clientID, counter), plain, aad)
if err != nil {
return nil, err
}
@@ -39,47 +29,5 @@ func sealDatagram(key, prefix []byte, clientID uint16, counter uint32, aad, plai
}
func openDatagram(key, prefix []byte, clientID uint16, counter uint32, aad, tag, ct []byte) ([]byte, error) {
return openTrunc(key, ivFor(prefix, clientID, counter), tag, ct, aad)
}
// The protocol's tag is 8 bytes. crypto/cipher only builds GCM tags of 12 to 16
// bytes, and an 8-byte tag is the leading 8 bytes of the ordinary 16-byte tag.
func sealTrunc(key, nonce, plain, aad []byte) (tag, ct []byte, err error) {
g, err := gcmFull(key)
if err != nil {
return nil, nil, err
}
out := g.Seal(nil, nonce, plain, aad)
ct = append([]byte(nil), out[:len(plain)]...)
tag = append([]byte(nil), out[len(plain):len(plain)+8]...)
return tag, ct, nil
}
func openTrunc(key, nonce, tag, ct, aad []byte) ([]byte, error) {
if len(tag) != 8 {
return nil, errors.New("tag")
}
g, err := gcmFull(key)
if err != nil {
return nil, err
}
stream := g.Seal(nil, nonce, make([]byte, len(ct)), aad)
plain := make([]byte, len(ct))
subtle.XORBytes(plain, ct, stream[:len(ct)])
check := g.Seal(nil, nonce, plain, aad)
var got, want [8]byte
copy(got[:], tag)
copy(want[:], check[len(plain):len(plain)+8])
if subtle.ConstantTimeCompare(got[:], want[:]) != 1 {
return nil, errors.New("tag")
}
return plain, nil
}
func gcmFull(key []byte) (cipher.AEAD, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return cipher.NewGCM(block)
return gcm64.Open(key, gcm64.IV(prefix, clientID, counter), tag, ct, aad)
}