cmd/age-keygen,extra/age-plugin-pq: buffer identity conversion output

Reported by Joe Doyle of Trail of Bits.
This commit is contained in:
Filippo Valsorda
2026-08-29 19:30:10 +02:00
parent 019df184df
commit aaadae2d85
4 changed files with 50 additions and 28 deletions
+21 -15
View File
@@ -92,6 +92,20 @@ func main() {
errorf("-pq cannot be used with -y")
}
var converted []byte
if convertFlag {
in := os.Stdin
if inFile := flag.Arg(0); inFile != "" && inFile != "-" {
f, err := os.Open(inFile)
if err != nil {
errorf("failed to open input file %q: %v", inFile, err)
}
defer f.Close()
in = f
}
converted = convert(in)
}
out := os.Stdout
if outFlag != "" {
f, err := os.OpenFile(outFlag, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
@@ -106,18 +120,8 @@ func main() {
out = f
}
in := os.Stdin
if inFile := flag.Arg(0); inFile != "" && inFile != "-" {
f, err := os.Open(inFile)
if err != nil {
errorf("failed to open input file %q: %v", inFile, err)
}
defer f.Close()
in = f
}
if convertFlag {
convert(in, out)
writef(out, "%s", converted)
} else {
if fi, err := out.Stat(); err == nil && fi.Mode().IsRegular() && fi.Mode().Perm()&0004 != 0 {
warning("writing secret key to a world-readable file")
@@ -160,7 +164,7 @@ func writef(out io.Writer, format string, v ...any) {
}
}
func convert(in io.Reader, out io.Writer) {
func convert(in io.Reader) []byte {
ids, err := age.ParseIdentities(in)
if err != nil {
errorf("failed to parse input: %v", err)
@@ -168,17 +172,19 @@ func convert(in io.Reader, out io.Writer) {
if len(ids) == 0 {
errorf("no identities found in the input")
}
var out []byte
for _, id := range ids {
switch id := id.(type) {
case *age.X25519Identity:
writef(out, "%s\n", id.Recipient())
out = append(out, id.Recipient().String()...)
case *age.HybridIdentity:
writef(out, "%s\n", id.Recipient())
out = append(out, id.Recipient().String()...)
default:
errorf("internal error: unexpected identity type: %T", id)
}
out = append(out, '\n')
}
return out
}
func errorf(format string, v ...any) {
+7
View File
@@ -39,9 +39,16 @@ age -d -i key.txt test.age
cmp stdout input
! stderr .
! exec age-plugin-pq -identity -o mixed-plugin.txt mixed.txt
stderr 'identity #2 is not a post-quantum hybrid identity'
! exists mixed-plugin.txt
-- input --
test
-- key.txt --
# created: 2025-11-17T13:27:37+01:00
# public key: age1pq1044e3hfmq2tltgck54m0gnpv8rfrwkdxjgl38psnwg8zfyv4uqdu63kk0u94ztt0q35k9dzuwgv405kxq6due2sre2kfsjftf7k2vz2mdpetku9pufy9d6ny6k5ss0cghpxdxrux0yd5xy40f8fu8ch9xn2rczyek2pqetqk0l9fqj0e3hfhkyfmcf9j6cpe5mf5stt9cymfq3xm276x4sramhn8srr42g78q9rkmqesevy33p4kdhkuggl99x9zx7j05uflx3s8q558xeaq9q9ctxqx52rzg6yffwykxngvxf7g3n83ddawagq2lnk59kcnexm54jrsmkjk9nemlge9v6p7fxu5z6yvq3ghpet8ww2c3h9fylvjx6j9njwz744376ap5r3xcpzh7qlk0kq3gknzfqhmxmjqypf6xz6geffdmy25apzsfr4ce0x825njkf62mgzx0x9n3zt0490u4dnt4468zse4zvd9sv0ycx2u2wsseuy4yymrg0nmfuxcwq9q0jykq7g5f59vunf95vnmcw336ksrh43fgapsd40u4227ymx56xtudtrte39twnq6fdfdj4p9pgx7pcqdk953za76fqcnvatx2cmywurag7ky4y8ecq5lvf25rydhxg6gmcn6vf78vtsqw79hp3mzv2u4v4jzn0nk50kl4gpv7k60cgz79c6k30jzy8dyetqtwg04tguxkv2p4hqj02yvsz2szaqdn9flu24rhth3v0t33023nwy27gt0x32eqpa5tpz6ygz3yzcsa3w889drpynzd5hlywuk9dwgafuax7upfnnxch4znrx4vactasg32u7vl886pxfswskk7wjgqkggrewtnaecfusl3nmg0xxh8e5nl5eft0xqwj5rk9ajn2j6yxehhgg5k6kpw5pk382hxmpu8wcd3rqx6m8905c7f8v0x2z9gyduxtqp2fdy9w2z4g2rrgu4d5cqes5tnwag007h2f326s3j9p6970xyd73rv5awx27zzezrax467c6vuye62ha88pzhw9xytjpezw3vg3l6x4k9rxwm9f6lwj6j7r9makg59rhgt0355s3jx9vw3raz5qdk5cnpny56q5h3dyd75suskuz63wmmfp9333tx4ry38vnh7jxy0j0cka99y7v2dmyjldjy0mqjetcefsmmg3pw0h9ll0rtskpmxz2cs8vmx6lu4v5rjtzpzgaqt46cwvnmhy5e3ye0tv6sre342lwg0tfd0yjkfz2haqc3hprpqf5ce8c9lx076dnk5cukn3tu38jgprrxt9sk9nqzt8grvkc4qzlg8jjf638v07ej9cf4eu48kphrgyjy83qm822xq8v9k22zwa7txr439x74j2f9ay7frkwtfdwn02enyx8stjpr4wgg25n5tj7uxyx0dqt3hnrqf7dcgt9fqnkjgemjfzyck6pawewptcayxm49sq3477f4cvm2p8fmg27rcmwm5l2vmzvdmymvkrr3aywu04y3zlhs7awu3r9u9lseheqpffvm2xf8y6w2qaj9g22pcu0sdsnqseusrxq9awru5lyqxnzftlslgpe3njegxkze98rveswp3u0xgx69wkg38vgp4k55lwwgv5l7ccv503mh9q23nud4xtm499xq276u40rxyrzaqfyuz2f3v5qr2vq00xs4g3ruynmq0c6nprvjcwqc5zrdn4cnzeeuwumjvqfjdpxr739n4cqcwytc8pjmfcj2qs3l2a8p5fzq7nvtng2jvvklx0x5ypnlkeuegsm587f6d4dkwel2es0lwwt88y2jdg8enjyph02tnjyndlx34h52fngjk96ggtu6vcxqkreqcxs4gwa8ww40t0kzlxfzyfhtjmfdm5fcrr5pt2xm4yslfynr0h9wkranhyadxf33kjn9xpg2fq5hnlq0
AGE-SECRET-KEY-PQ-16XDSLZ3XCSZ3236YJ5J0T9NAPLZTP96LJKQCVHJYUDTQVJR5J5PQTDPQCX
-- mixed.txt --
AGE-SECRET-KEY-PQ-16XDSLZ3XCSZ3236YJ5J0T9NAPLZTP96LJKQCVHJYUDTQVJR5J5PQTDPQCX
AGE-SECRET-KEY-1EGTZVFFV20835NWYV6270LXYVK2VKNX2MMDKWYKLMGR48UAWX40Q2P2LM0
+4
View File
@@ -23,3 +23,7 @@ stdout age1pq1
exec age-keygen -y key.txt
stdout age1pq1
! exec age-keygen -y -o missing.txt missing
stderr 'failed to open input file'
! exists missing.txt
+18 -13
View File
@@ -66,6 +66,17 @@ func main() {
errorf("too many arguments")
}
in := os.Stdin
if inFile := flag.Arg(0); inFile != "" && inFile != "-" {
f, err := os.Open(inFile)
if err != nil {
errorf("failed to open input file %q: %v", inFile, err)
}
defer f.Close()
in = f
}
converted := convert(in)
out := os.Stdout
if outFlag != "" {
f, err := os.OpenFile(outFlag, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
@@ -82,18 +93,9 @@ func main() {
if fi, err := out.Stat(); err == nil && fi.Mode().IsRegular() && fi.Mode().Perm()&0004 != 0 {
warning("writing secret key to a world-readable file")
}
in := os.Stdin
if inFile := flag.Arg(0); inFile != "" && inFile != "-" {
f, err := os.Open(inFile)
if err != nil {
errorf("failed to open input file %q: %v", inFile, err)
}
defer f.Close()
in = f
if _, err := out.Write(converted); err != nil {
errorf("failed to write output: %v", err)
}
convert(in, out)
return
}
@@ -123,11 +125,12 @@ func main() {
os.Exit(p.Main())
}
func convert(in io.Reader, out io.Writer) {
func convert(in io.Reader) []byte {
ids, err := age.ParseIdentities(in)
if err != nil {
errorf("failed to parse identities: %v", err)
}
var out []byte
for i, id := range ids {
hybridID, ok := id.(*age.HybridIdentity)
if !ok {
@@ -137,8 +140,10 @@ func convert(in io.Reader, out io.Writer) {
if err != nil {
errorf("failed to decode identity #%d: %v", i+1, err)
}
fmt.Fprintln(out, plugin.EncodeIdentity("pq", data))
out = append(out, plugin.EncodeIdentity("pq", data)...)
out = append(out, '\n')
}
return out
}
func errorf(format string, v ...any) {