commit 3e942aad1e42e2e9380a7203b6187a827477b1fa
parent 5449f48e21138128d9936541f3d5dbf2eeba3b76
Author: david cochran <about.trout@gmail.com>
Date: Tue, 4 Nov 2025 06:32:35 -0800
add layer5 solution
Diffstat:
| A | cmd/layer5/decode.go | | | 86 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 86 insertions(+), 0 deletions(-)
diff --git a/cmd/layer5/decode.go b/cmd/layer5/decode.go
@@ -0,0 +1,86 @@
+package main
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "encoding/binary"
+ "errors"
+ "log"
+ "os"
+
+ "github.com/abtrout/tdo"
+)
+
+func main() {
+ bs, err := tdo.DecodePipedInput()
+ if err != nil {
+ log.Fatalf("Failed to read layer input: %v", err)
+ }
+
+ // Split input based on instructions.
+ kek := bs[0:32]
+ keyIV, keyCT := bs[32:40], bs[40:80]
+ ctIV, ct := bs[80:96], bs[96:]
+ // Decrypt the key with kek and keyIV.
+ block, err := aes.NewCipher(kek)
+ if err != nil {
+ log.Fatalf("Failed to make NewCipher: %v", err)
+ }
+ key, err := KeyUnwrap(block, keyIV, keyCT)
+ if err != nil {
+ log.Fatalf("Failed to unwrap key: %v", err)
+ }
+ // Decrypt the ct with key and iv.
+ block, err = aes.NewCipher(key)
+ if err != nil {
+ log.Fatalf("Failed to make NewCipher: %v", err)
+ }
+ out := make([]byte, len(ct))
+ stream := cipher.NewCTR(block, ctIV)
+ stream.XORKeyStream(out, ct)
+
+ if _, err := os.Stdout.Write(out); err != nil {
+ log.Fatalf("Failed to write decoded output: %v", err)
+ }
+}
+
+// Key Unwrap is not implemented in the standard library.
+// https://datatracker.ietf.org/doc/html/rfc3394#section-2.2.2
+func KeyUnwrap(block cipher.Block, iv, ct []byte) ([]byte, error) {
+ // setup
+ a := make([]byte, 8)
+ copy(a, ct[0:8])
+ n := (len(ct) / 8) - 1 // n+1 blocks
+ r := make([][]byte, n)
+ for i := range r {
+ r[i] = ct[(i+1)*8 : (i+2)*8]
+ }
+ // unwrap
+ ctr := make([]byte, 8)
+ for j := 5; j >= 0; j-- {
+ for i := len(r) - 1; i >= 0; i-- {
+ binary.BigEndian.PutUint64(ctr, uint64(n*j+i+1))
+ // a = a ^ ctr
+ for i := range a {
+ a[i] ^= ctr[i]
+ }
+ // b = Decrypt(a || r[i])
+ b := append(a, r[i]...)
+ block.Decrypt(b, b)
+ // reset for next round
+ copy(a, b[0:8])
+ copy(r[i], b[8:16])
+ }
+ }
+ // verify
+ if !bytes.Equal(a, iv) {
+ return nil, errors.New("iv mismatch")
+ }
+ // output
+ var res []byte
+ for _, b := range r {
+ res = append(res, b...)
+ }
+ return res, nil
+}