Skip to content

Commit dfc7c39

Browse files
authored
Merge pull request #767 from jetstack/jwe
Convert RSA envelope encryption to JWE
2 parents bd72b13 + 666d6bf commit dfc7c39

File tree

8 files changed

+181
-151
lines changed

8 files changed

+181
-151
lines changed

LICENSES

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ github.com/hashicorp/errwrap,MPL-2.0
7373
github.com/hashicorp/go-multierror,MPL-2.0
7474
github.com/josharian/intern,MIT
7575
github.com/json-iterator/go,MIT
76+
github.com/lestrrat-go/blackmagic,MIT
77+
github.com/lestrrat-go/httpcc,MIT
78+
github.com/lestrrat-go/httprc/v3,MIT
79+
github.com/lestrrat-go/jwx/v3,MIT
80+
github.com/lestrrat-go/option/v2,MIT
7681
github.com/mailru/easyjson,MIT
7782
github.com/mattn/go-colorable,MIT
7883
github.com/mattn/go-isatty,MIT

go.mod

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/google/uuid v1.6.0
1111
github.com/hashicorp/go-multierror v1.1.1
1212
github.com/jetstack/venafi-connection-lib v0.5.2
13+
github.com/lestrrat-go/jwx/v3 v3.0.13
1314
github.com/microcosm-cc/bluemonday v1.0.27
1415
github.com/pmylund/go-cache v2.1.0+incompatible
1516
github.com/prometheus/client_golang v1.23.2
@@ -32,22 +33,29 @@ require (
3233
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
3334
github.com/aymerick/douceur v0.2.0 // indirect
3435
github.com/blang/semver/v4 v4.0.0 // indirect
36+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
3537
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
3638
github.com/fsnotify/fsnotify v1.9.0 // indirect
3739
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
3840
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect
3941
github.com/go-logr/zapr v1.3.0 // indirect
4042
github.com/go418/concurrentcache v0.6.0 // indirect
4143
github.com/go418/concurrentcache/logger v0.0.0-20250207095056-c0b7f8cc8bc2 // indirect
44+
github.com/goccy/go-json v0.10.3 // indirect
4245
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
4346
github.com/google/btree v1.1.3 // indirect
4447
github.com/google/cel-go v0.26.0 // indirect
4548
github.com/google/gnostic-models v0.7.0 // indirect
4649
github.com/gorilla/css v1.0.1 // indirect
4750
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
4851
github.com/json-iterator/go v1.1.12 // indirect
52+
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
53+
github.com/lestrrat-go/httpcc v1.0.1 // indirect
54+
github.com/lestrrat-go/httprc/v3 v3.0.2 // indirect
55+
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
4956
github.com/pkg/errors v0.9.1 // indirect
5057
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
58+
github.com/segmentio/asm v1.2.1 // indirect
5159
github.com/sosodev/duration v1.3.1 // indirect
5260
github.com/stoewer/go-strcase v1.3.0 // indirect
5361
github.com/vektah/gqlparser/v2 v2.5.30 // indirect
@@ -59,7 +67,7 @@ require (
5967
go.uber.org/zap v1.27.0 // indirect
6068
go.yaml.in/yaml/v2 v2.4.2 // indirect
6169
go.yaml.in/yaml/v3 v3.0.4 // indirect
62-
golang.org/x/crypto v0.45.0 // indirect
70+
golang.org/x/crypto v0.46.0 // indirect
6371
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
6472
golang.org/x/net v0.47.0 // indirect
6573
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
@@ -98,9 +106,9 @@ require (
98106
github.com/prometheus/common v0.66.1 // indirect
99107
github.com/prometheus/procfs v0.16.1 // indirect
100108
golang.org/x/oauth2 v0.30.0 // indirect
101-
golang.org/x/sys v0.38.0 // indirect
102-
golang.org/x/term v0.37.0 // indirect
103-
golang.org/x/text v0.31.0 // indirect
109+
golang.org/x/sys v0.39.0 // indirect
110+
golang.org/x/term v0.38.0 // indirect
111+
golang.org/x/text v0.32.0 // indirect
104112
golang.org/x/time v0.9.0 // indirect
105113
google.golang.org/protobuf v1.36.8 // indirect
106114
gopkg.in/inf.v0 v0.9.1 // indirect

go.sum

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
2929
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3030
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
3131
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
32+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
33+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
3234
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
3335
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
3436
github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
@@ -63,6 +65,8 @@ github.com/go418/concurrentcache v0.6.0 h1:36A7j+c0dChEAMotq+lBQwQPyI4CMCy5HgMCc
6365
github.com/go418/concurrentcache v0.6.0/go.mod h1:F498AylMP488QhU9KSE8VoN3u2FhGt7hXOgJ2CdvysM=
6466
github.com/go418/concurrentcache/logger v0.0.0-20250207095056-c0b7f8cc8bc2 h1:wVvBhfD+7srZ470Z06t5rp93faukGddvUJR4+owL0Kw=
6567
github.com/go418/concurrentcache/logger v0.0.0-20250207095056-c0b7f8cc8bc2/go.mod h1:DpmmUFByr4p8fGMbp2gsGJhqgcP1SXjyVZDiW0f8aSY=
68+
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
69+
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
6670
github.com/goccy/go-yaml v1.19.0 h1:EmkZ9RIsX+Uq4DYFowegAuJo8+xdX3T/2dwNPXbxEYE=
6771
github.com/goccy/go-yaml v1.19.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
6872
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -119,6 +123,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
119123
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
120124
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
121125
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
126+
github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
127+
github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
128+
github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38=
129+
github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo=
130+
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY=
131+
github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU=
132+
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
133+
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
134+
github.com/lestrrat-go/httprc/v3 v3.0.2 h1:7u4HUaD0NQbf2/n5+fyp+T10hNCsAnwKfqn4A4Baif0=
135+
github.com/lestrrat-go/httprc/v3 v3.0.2/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0=
136+
github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk=
137+
github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU=
138+
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
139+
github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg=
122140
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
123141
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
124142
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -158,6 +176,8 @@ github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlT
158176
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
159177
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
160178
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
179+
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
180+
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
161181
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
162182
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
163183
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
@@ -180,6 +200,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
180200
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
181201
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
182202
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
203+
github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM=
204+
github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
183205
github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE=
184206
github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
185207
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
@@ -229,8 +251,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
229251
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
230252
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
231253
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
232-
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
233-
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
254+
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
255+
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
234256
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
235257
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
236258
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -253,22 +275,22 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
253275
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
254276
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
255277
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
256-
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
257-
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
258-
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
259-
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
278+
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
279+
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
280+
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
281+
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
260282
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
261283
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
262-
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
263-
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
284+
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
285+
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
264286
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
265287
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
266288
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
267289
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
268290
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
269291
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
270-
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
271-
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
292+
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
293+
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
272294
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
273295
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
274296
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

internal/envelope/doc.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// Package envelope provides types and interfaces for envelope encryption.
22
//
33
// Envelope encryption combines asymmetric and symmetric cryptography to
4-
// efficiently encrypt data. The EncryptedData type holds the result, and
5-
// the Encryptor interface defines the encryption operation.
4+
// efficiently encrypt data. The Encryptor interface defines the encryption
5+
// operation, returning data in JWE (JSON Web Encryption) format as defined
6+
// in RFC 7516.
67
//
78
// Implementations are available in subpackages:
89
//
9-
// - internal/envelope/rsa: RSA-OAEP + AES-256-GCM
10+
// - internal/envelope/rsa: RSA-OAEP-256 + AES-256-GCM using JWE
1011
//
1112
// See subpackage documentation for usage examples.
1213
package envelope

internal/envelope/rsa/doc.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1-
// Package rsa implements RSA envelope encryption, conforming to the interface in the envelope package.
2-
// It uses RSA-OAEP with SHA-256 for key encryption, and AES-256-GCM for data encryption.
1+
// Package rsa implements RSA envelope encryption using JWE (JSON Web Encryption) format.
2+
// It conforms to the interface in the envelope package.
3+
//
4+
// The implementation uses:
5+
// - RSA-OAEP-256 (RSA-OAEP with SHA-256) for key encryption
6+
// - AES-256-GCM (A256GCM) for content encryption
7+
// - JWE Compact Serialization format as defined in RFC 7516
8+
//
9+
// The output is a JWE string with 5 base64url-encoded parts separated by dots:
10+
// header.encryptedKey.iv.ciphertext.tag
311
package rsa

internal/envelope/rsa/encryptor.go

Lines changed: 31 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,37 @@
11
package rsa
22

33
import (
4-
"crypto/aes"
5-
"crypto/cipher"
6-
"crypto/rand"
74
"crypto/rsa"
8-
"crypto/sha256"
95
"fmt"
106

7+
"github.com/lestrrat-go/jwx/v3/jwa"
8+
"github.com/lestrrat-go/jwx/v3/jwe"
9+
1110
"github.com/jetstack/preflight/internal/envelope"
1211
)
1312

1413
const (
15-
// aesKeySize is the size of the AES-256 key in bytes; aes.NewCipher generates cipher.Block based
16-
// on the size of key passed in, and 32 bytes corresponds to a 256-bit AES key
17-
aesKeySize = 32
18-
1914
// minRSAKeySize is the minimum RSA key size in bits; we'd expect that keys will be larger but 2048 is a sane floor
2015
// to enforce to ensure that a weak key can't accidentally be used
2116
minRSAKeySize = 2048
2217

23-
// keyAlgorithmIdentifier is set in EncryptedData to identify the key wrapping algorithm used in this package
24-
keyAlgorithmIdentifier = "RSA-OAEP-SHA256"
18+
// EncryptionType is the type identifier for RSA JWE encryption
19+
EncryptionType = "JWE-RSA"
2520
)
2621

2722
// Compile-time check that Encryptor implements envelope.Encryptor
2823
var _ envelope.Encryptor = (*Encryptor)(nil)
2924

30-
// Encryptor provides envelope encryption using RSA for key wrapping
31-
// and AES-256-GCM for data encryption.
25+
// Encryptor provides envelope encryption using RSA-OAEP-256 for key wrapping
26+
// and AES-256-GCM for data encryption, outputting JWE Compact Serialization format.
3227
type Encryptor struct {
33-
keyID string
34-
rsaPublicKey *rsa.PublicKey
28+
keyID string
29+
publicKey *rsa.PublicKey
3530
}
3631

3732
// NewEncryptor creates a new Encryptor with the provided RSA public key.
38-
// The RSA key must be at least minRSAKeySize bits
33+
// The RSA key must be at least minRSAKeySize bits.
34+
// The encryptor will use RSA-OAEP-256 for key encryption and A256GCM for content encryption.
3935
func NewEncryptor(keyID string, publicKey *rsa.PublicKey) (*Encryptor, error) {
4036
if publicKey == nil {
4137
return nil, fmt.Errorf("RSA public key cannot be nil")
@@ -52,77 +48,39 @@ func NewEncryptor(keyID string, publicKey *rsa.PublicKey) (*Encryptor, error) {
5248
}
5349

5450
return &Encryptor{
55-
keyID: keyID,
56-
rsaPublicKey: publicKey,
51+
keyID: keyID,
52+
publicKey: publicKey,
5753
}, nil
5854
}
5955

6056
// Encrypt performs envelope encryption on the provided data.
61-
// It generates a random AES-256 key, encrypts the data with AES-256-GCM,
62-
// then encrypts the AES key with RSA-OAEP-SHA256.
57+
// It returns an EncryptedData struct containing JWE Compact Serialization format and type metadata.
58+
// The JWE uses RSA-OAEP-256 for key encryption and A256GCM for content encryption.
6359
func (e *Encryptor) Encrypt(data []byte) (*envelope.EncryptedData, error) {
6460
if len(data) == 0 {
6561
return nil, fmt.Errorf("data to encrypt cannot be empty")
6662
}
6763

68-
aesKey := make([]byte, aesKeySize)
69-
if _, err := rand.Read(aesKey); err != nil {
70-
return nil, fmt.Errorf("failed to generate AES key: %w", err)
71-
}
72-
73-
// zero the key from memory before the function returns
74-
// TODO: in go1.26+, consider using secret.Do in this function
75-
defer func() {
76-
for i := range aesKey {
77-
aesKey[i] = 0
78-
}
79-
}()
80-
81-
block, err := aes.NewCipher(aesKey)
82-
if err != nil {
83-
return nil, fmt.Errorf("failed to create AES cipher: %w", err)
84-
}
85-
86-
gcm, err := cipher.NewGCM(block)
87-
if err != nil {
88-
return nil, fmt.Errorf("failed to create GCM cipher: %w", err)
89-
}
90-
91-
encryptedData := &envelope.EncryptedData{
92-
KeyID: e.keyID,
93-
KeyAlgorithm: keyAlgorithmIdentifier,
94-
EncryptedKey: nil,
95-
EncryptedData: nil,
96-
Nonce: make([]byte, gcm.NonceSize()),
97-
}
98-
99-
// Generate a random nonce for AES-GCM.
100-
// Security: Nonces must never be re-used for a given key. Since we generate a new AES key for each encryption,
101-
// the risk of nonce reuse is not a concern here.
102-
if _, err := rand.Read(encryptedData.Nonce); err != nil {
103-
return nil, fmt.Errorf("failed to generate nonce: %w", err)
64+
// Create headers with the key ID
65+
headers := jwe.NewHeaders()
66+
if err := headers.Set("kid", e.keyID); err != nil {
67+
return nil, fmt.Errorf("failed to set key ID header: %w", err)
10468
}
10569

106-
// Seal encrypts and authenticates the data. This could include additional authenticated data,
107-
// but we don't make use of that here.
108-
// First nil: allocate new slice for output.
109-
// Last nil: no additional authenticated data (AAD) needed.
110-
111-
encryptedData.EncryptedData = gcm.Seal(nil, encryptedData.Nonce, data, nil)
112-
113-
// Encrypt AES key with RSA-OAEP-SHA256. The nil parameter means no additional
114-
// context data is mixed into the hash; this could be used to disambiguate different uses of the same key,
115-
// but we only have one use for the key here.
116-
encryptedData.EncryptedKey, err = rsa.EncryptOAEP(
117-
sha256.New(),
118-
rand.Reader,
119-
e.rsaPublicKey,
120-
aesKey,
121-
nil,
70+
// Encrypt using RSA-OAEP-256 for key algorithm and A256GCM for content encryption
71+
// TODO: in go1.26+, consider using secret.Do to wrap this call, since it will generate an AES key
72+
encrypted, err := jwe.Encrypt(
73+
data,
74+
jwe.WithKey(jwa.RSA_OAEP_256(), e.publicKey, jwe.WithPerRecipientHeaders(headers)),
75+
jwe.WithContentEncryption(jwa.A256GCM()),
76+
jwe.WithCompact(),
12277
)
12378
if err != nil {
124-
return nil, fmt.Errorf("failed to encrypt AES key with RSA: %w", err)
79+
return nil, fmt.Errorf("failed to encrypt data: %w", err)
12580
}
12681

127-
return encryptedData, nil
82+
return &envelope.EncryptedData{
83+
Data: encrypted,
84+
Type: EncryptionType,
85+
}, nil
12886
}

0 commit comments

Comments
 (0)