55import java .util .ArrayList ;
66import java .util .Collections ;
77import java .util .List ;
8+ import java .util .Map ;
89import software .amazon .cryptography .dbencryptionsdk .dynamodb .model .BeaconVersion ;
910import software .amazon .cryptography .dbencryptionsdk .dynamodb .model .CompoundBeacon ;
1011import software .amazon .cryptography .dbencryptionsdk .dynamodb .model .EncryptedPart ;
@@ -24,12 +25,35 @@ public static final class SearchInfo {
2425 public final List <StandardBeaconImpl > standardBeacons ;
2526 public final List <CompoundBeaconImpl > compoundBeacons ;
2627 public final BeaconVersion beaconVersion ;
28+ public final software .amazon .cryptography .keystore .KeyStore keyStore ;
29+ public final String beaconKeyId ;
2730
2831 public SearchInfo (List <StandardBeaconImpl > standardBeacons , List <CompoundBeaconImpl > compoundBeacons ,
2932 BeaconVersion beaconVersion ) {
3033 this .standardBeacons = standardBeacons ;
3134 this .compoundBeacons = compoundBeacons ;
3235 this .beaconVersion = beaconVersion ;
36+ this .keyStore = beaconVersion .keyStore ();
37+ // Extract key ID from key source
38+ if (beaconVersion .keySource () != null && beaconVersion .keySource ().single () != null ) {
39+ this .beaconKeyId = beaconVersion .keySource ().single ().keyId ();
40+ } else {
41+ this .beaconKeyId = null ;
42+ }
43+ }
44+
45+ /** Get the HMAC key bytes from the beacon key store. Returns null if not configured. */
46+ public byte [] getHmacKey () {
47+ if (keyStore == null || beaconKeyId == null ) return null ;
48+ software .amazon .cryptography .keystore .model .GetBeaconKeyOutput output =
49+ keyStore .GetBeaconKey (software .amazon .cryptography .keystore .model .GetBeaconKeyInput .builder ()
50+ .branchKeyIdentifier (beaconKeyId ).build ());
51+ java .nio .ByteBuffer keyBuf = output .beaconKeyMaterials ().beaconKey ();
52+ if (keyBuf == null ) return null ;
53+ keyBuf = keyBuf .asReadOnlyBuffer ();
54+ byte [] key = new byte [keyBuf .remaining ()];
55+ keyBuf .get (key );
56+ return key ;
3357 }
3458 }
3559
@@ -53,7 +77,11 @@ private static List<StandardBeaconImpl> resolveStandardBeacons(BeaconVersion ver
5377 if (version .standardBeacons () == null ) return Collections .emptyList ();
5478 List <StandardBeaconImpl > result = new ArrayList <>();
5579 for (StandardBeacon sb : version .standardBeacons ()) {
56- result .add (new StandardBeaconImpl (sb .name (), sb .length ()));
80+ boolean isSet = false ;
81+ if (sb .style () != null ) {
82+ isSet = sb .style ().asSet () != null || sb .style ().sharedSet () != null ;
83+ }
84+ result .add (new StandardBeaconImpl (sb .name (), sb .length (), isSet ));
5785 }
5886 return result ;
5987 }
@@ -62,25 +90,84 @@ private static List<CompoundBeaconImpl> resolveCompoundBeacons(
6290 BeaconVersion version , List <StandardBeaconImpl > standards
6391 ) {
6492 if (version .compoundBeacons () == null ) return Collections .emptyList ();
93+
94+ // Build a map of encrypted parts from both version-level and compound-level
95+ Map <String , EncryptedPart > versionEncParts = new java .util .HashMap <>();
96+ if (version .encryptedParts () != null ) {
97+ for (EncryptedPart ep : version .encryptedParts ()) {
98+ versionEncParts .put (ep .name (), ep );
99+ }
100+ }
101+ Map <String , SignedPart > versionSigParts = new java .util .HashMap <>();
102+ if (version .signedParts () != null ) {
103+ for (SignedPart sp : version .signedParts ()) {
104+ versionSigParts .put (sp .name (), sp );
105+ }
106+ }
107+
65108 List <CompoundBeaconImpl > result = new ArrayList <>();
66109 for (CompoundBeacon cb : version .compoundBeacons ()) {
67110 char split = cb .split ().charAt (0 );
68111 List <CompoundBeaconImpl .EncryptedPart > encParts = new ArrayList <>();
69- if (cb .encrypted () != null ) {
112+ List <CompoundBeaconImpl .SignedPart > sigParts = new ArrayList <>();
113+
114+ // Use compound-level parts if defined, otherwise use version-level parts via constructors
115+ if (cb .encrypted () != null && !cb .encrypted ().isEmpty ()) {
70116 for (EncryptedPart ep : cb .encrypted ()) {
71117 StandardBeaconImpl beacon = findBeacon (standards , ep .name ());
72118 if (beacon != null ) {
73119 encParts .add (new CompoundBeaconImpl .EncryptedPart (ep .prefix (), beacon ));
74120 }
75121 }
76122 }
77- List <CompoundBeaconImpl .SignedPart > sigParts = new ArrayList <>();
78- if (cb .signed () != null ) {
123+ if (cb .signed () != null && !cb .signed ().isEmpty ()) {
79124 for (SignedPart sp : cb .signed ()) {
80125 sigParts .add (new CompoundBeaconImpl .SignedPart (sp .prefix (), sp .name ()));
81126 }
82127 }
83- result .add (new CompoundBeaconImpl (cb .name (), split , encParts , sigParts ));
128+
129+ // If no parts from compound-level, resolve from constructors using version-level parts
130+ if (encParts .isEmpty () && sigParts .isEmpty () && cb .constructors () != null ) {
131+ java .util .Set <String > seenEncParts = new java .util .HashSet <>();
132+ java .util .Set <String > seenSigParts = new java .util .HashSet <>();
133+ for (software .amazon .cryptography .dbencryptionsdk .dynamodb .model .Constructor ctor : cb .constructors ()) {
134+ if (ctor .parts () != null ) {
135+ for (software .amazon .cryptography .dbencryptionsdk .dynamodb .model .ConstructorPart cp : ctor .parts ()) {
136+ String partName = cp .name ();
137+ // Check if it's an encrypted part
138+ EncryptedPart ep = versionEncParts .get (partName );
139+ if (ep != null && seenEncParts .add (partName )) {
140+ StandardBeaconImpl beacon = findBeacon (standards , ep .name ());
141+ if (beacon != null ) {
142+ encParts .add (new CompoundBeaconImpl .EncryptedPart (ep .prefix (), beacon ));
143+ }
144+ } else {
145+ // Check if it's a signed part
146+ SignedPart sp = versionSigParts .get (partName );
147+ if (sp != null && seenSigParts .add (partName )) {
148+ sigParts .add (new CompoundBeaconImpl .SignedPart (sp .prefix (), sp .name ()));
149+ }
150+ }
151+ }
152+ }
153+ }
154+ }
155+
156+ // Build constructor part name lists for ordered construction
157+ List <List <String >> ctorPartNames = new ArrayList <>();
158+ if (cb .constructors () != null ) {
159+ for (software .amazon .cryptography .dbencryptionsdk .dynamodb .model .Constructor ctor : cb .constructors ()) {
160+ if (ctor .parts () != null ) {
161+ List <String > partNames = new ArrayList <>();
162+ for (software .amazon .cryptography .dbencryptionsdk .dynamodb .model .ConstructorPart cp : ctor .parts ()) {
163+ partNames .add (cp .name ());
164+ }
165+ ctorPartNames .add (partNames );
166+ }
167+ }
168+ }
169+
170+ result .add (new CompoundBeaconImpl (cb .name (), split , encParts , sigParts , ctorPartNames ));
84171 }
85172 return result ;
86173 }
0 commit comments