@@ -977,6 +977,185 @@ public void GenericRecordFieldEncryption()
977
977
Assert . True ( pic . SequenceEqual ( ( byte [ ] ) result [ "picture" ] ) ) ;
978
978
}
979
979
980
+ [ Fact ]
981
+ public void GenericRecordFieldEncryptionF1Preserialized ( )
982
+ {
983
+ var schemaStr = "{\" type\" :\" record\" ,\" name\" :\" myrecord\" ," +
984
+ "\" fields\" :[{\" name\" :\" f1\" ,\" type\" :\" string\" }]}" ;
985
+
986
+ var schema = new RegisteredSchema ( "topic-value" , 1 , 1 , schemaStr , SchemaType . Avro , null ) ;
987
+ schema . Metadata = new Metadata ( new Dictionary < string , ISet < string > >
988
+ {
989
+ [ "myrecord.f1" ] = new HashSet < string > { "PII" } ,
990
+
991
+ } , new Dictionary < string , string > ( ) , new HashSet < string > ( )
992
+ ) ;
993
+ schema . RuleSet = new RuleSet ( new List < Rule > ( ) ,
994
+ new List < Rule >
995
+ {
996
+ new Rule ( "encryptPII" , RuleKind . Transform , RuleMode . WriteRead , "ENCRYPT" , new HashSet < string >
997
+ {
998
+ "PII"
999
+ } , new Dictionary < string , string >
1000
+ {
1001
+ [ "encrypt.kek.name" ] = "kek1" ,
1002
+ [ "encrypt.kms.type" ] = "local-kms" ,
1003
+ [ "encrypt.kms.key.id" ] = "mykey"
1004
+ } )
1005
+ }
1006
+ ) ;
1007
+ store [ schemaStr ] = 1 ;
1008
+ subjectStore [ "topic-value" ] = new List < RegisteredSchema > { schema } ;
1009
+ var config = new AvroDeserializerConfig
1010
+ {
1011
+ } ;
1012
+ config . Set ( "rules.secret" , "mysecret" ) ;
1013
+ IRuleExecutor ruleExecutor = new FieldEncryptionExecutor ( dekRegistryClient , clock ) ;
1014
+ var deserializer = new AvroDeserializer < GenericRecord > ( schemaRegistryClient , config , new List < IRuleExecutor > { ruleExecutor } ) ;
1015
+
1016
+ kekStore [ new KekId ( "kek1" , false ) ] =
1017
+ new RegisteredKek ( )
1018
+ {
1019
+ Name = "kek1" ,
1020
+ KmsType = "local-kms" ,
1021
+ KmsKeyId = "mykey" ,
1022
+ } ;
1023
+ dekStore [ new DekId ( "kek1" , "topic-value" , 1 , DekFormat . AES256_GCM , false ) ] =
1024
+ new RegisteredDek ( )
1025
+ {
1026
+ Subject = "topic-value" ,
1027
+ Version = 1 ,
1028
+ Algorithm = DekFormat . AES256_GCM ,
1029
+ EncryptedKeyMaterial =
1030
+ "07V2ndh02DA73p+dTybwZFm7DKQSZN1tEwQh+FoX1DZLk4Yj2LLu4omYjp/84tAg3BYlkfGSz+zZacJHIE4=" ,
1031
+ } ;
1032
+ Headers headers = new Headers ( ) ;
1033
+ byte [ ] bytes = new byte [ ] { 0 , 0 , 0 , 0 , 1 , 104 , 122 , 103 , 121 , 47 , 106 , 70 , 78 , 77 , 86 , 47 , 101 , 70 , 105 , 108 , 97 , 72 , 114 , 77 , 121 , 101 , 66 , 103 , 100 , 97 , 86 , 122 , 114 , 82 , 48 , 117 , 100 , 71 , 101 , 111 , 116 , 87 , 56 , 99 , 65 , 47 , 74 , 97 , 108 , 55 , 117 , 107 , 114 , 43 , 77 , 47 , 121 , 122 } ;
1034
+ var result = deserializer . DeserializeAsync ( bytes , false , new SerializationContext ( MessageComponentType . Value , testTopic , headers ) ) . Result ;
1035
+
1036
+ Assert . Equal ( "hello world" , result [ "f1" ] ) ;
1037
+ }
1038
+
1039
+ [ Fact ]
1040
+ public void GenericRecordFieldEncryptionDeterministicF1Preserialized ( )
1041
+ {
1042
+ var schemaStr = "{\" type\" :\" record\" ,\" name\" :\" myrecord\" ," +
1043
+ "\" fields\" :[{\" name\" :\" f1\" ,\" type\" :\" string\" }]}" ;
1044
+
1045
+ var schema = new RegisteredSchema ( "topic-value" , 1 , 1 , schemaStr , SchemaType . Avro , null ) ;
1046
+ schema . Metadata = new Metadata ( new Dictionary < string , ISet < string > >
1047
+ {
1048
+ [ "myrecord.f1" ] = new HashSet < string > { "PII" } ,
1049
+
1050
+ } , new Dictionary < string , string > ( ) , new HashSet < string > ( )
1051
+ ) ;
1052
+ schema . RuleSet = new RuleSet ( new List < Rule > ( ) ,
1053
+ new List < Rule >
1054
+ {
1055
+ new Rule ( "encryptPII" , RuleKind . Transform , RuleMode . WriteRead , "ENCRYPT" , new HashSet < string >
1056
+ {
1057
+ "PII"
1058
+ } , new Dictionary < string , string >
1059
+ {
1060
+ [ "encrypt.kek.name" ] = "kek1" ,
1061
+ [ "encrypt.kms.type" ] = "local-kms" ,
1062
+ [ "encrypt.kms.key.id" ] = "mykey" ,
1063
+ [ "encrypt.dek.algorithm" ] = "AES256_SIV" ,
1064
+ } )
1065
+ }
1066
+ ) ;
1067
+ store [ schemaStr ] = 1 ;
1068
+ subjectStore [ "topic-value" ] = new List < RegisteredSchema > { schema } ;
1069
+ var config = new AvroDeserializerConfig
1070
+ {
1071
+ } ;
1072
+ config . Set ( "rules.secret" , "mysecret" ) ;
1073
+ IRuleExecutor ruleExecutor = new FieldEncryptionExecutor ( dekRegistryClient , clock ) ;
1074
+ var deserializer = new AvroDeserializer < GenericRecord > ( schemaRegistryClient , config , new List < IRuleExecutor > { ruleExecutor } ) ;
1075
+
1076
+ kekStore [ new KekId ( "kek1" , false ) ] =
1077
+ new RegisteredKek ( )
1078
+ {
1079
+ Name = "kek1" ,
1080
+ KmsType = "local-kms" ,
1081
+ KmsKeyId = "mykey" ,
1082
+ } ;
1083
+ dekStore [ new DekId ( "kek1" , "topic-value" , 1 , DekFormat . AES256_SIV , false ) ] =
1084
+ new RegisteredDek ( )
1085
+ {
1086
+ Subject = "topic-value" ,
1087
+ Version = 1 ,
1088
+ Algorithm = DekFormat . AES256_SIV ,
1089
+ EncryptedKeyMaterial =
1090
+ "YSx3DTlAHrmpoDChquJMifmPntBzxgRVdMzgYL82rgWBKn7aUSnG+WIu9ozBNS3y2vXd++mBtK07w4/W/G6w0da39X9hfOVZsGnkSvry/QRht84V8yz3dqKxGMOK5A==" ,
1091
+ } ;
1092
+ Headers headers = new Headers ( ) ;
1093
+ byte [ ] bytes = new byte [ ] { 0 , 0 , 0 , 0 , 1 , 72 , 68 , 54 , 89 , 116 , 120 , 114 , 108 , 66 , 110 , 107 , 84 , 87 , 87 , 57 , 78 , 54 , 86 , 98 , 107 , 51 , 73 , 73 , 110 , 106 , 87 , 72 , 56 , 49 , 120 , 109 , 89 , 104 , 51 , 107 , 52 , 100 } ;
1094
+ var result = deserializer . DeserializeAsync ( bytes , false , new SerializationContext ( MessageComponentType . Value , testTopic , headers ) ) . Result ;
1095
+
1096
+ Assert . Equal ( "hello world" , result [ "f1" ] ) ;
1097
+ }
1098
+
1099
+ [ Fact ]
1100
+ public void GenericRecordFieldEncryptionDekRotationF1Preserialized ( )
1101
+ {
1102
+ var schemaStr = "{\" type\" :\" record\" ,\" name\" :\" myrecord\" ," +
1103
+ "\" fields\" :[{\" name\" :\" f1\" ,\" type\" :\" string\" }]}" ;
1104
+
1105
+ var schema = new RegisteredSchema ( "topic-value" , 1 , 1 , schemaStr , SchemaType . Avro , null ) ;
1106
+ schema . Metadata = new Metadata ( new Dictionary < string , ISet < string > >
1107
+ {
1108
+ [ "myrecord.f1" ] = new HashSet < string > { "PII" } ,
1109
+
1110
+ } , new Dictionary < string , string > ( ) , new HashSet < string > ( )
1111
+ ) ;
1112
+ schema . RuleSet = new RuleSet ( new List < Rule > ( ) ,
1113
+ new List < Rule >
1114
+ {
1115
+ new Rule ( "encryptPII" , RuleKind . Transform , RuleMode . WriteRead , "ENCRYPT" , new HashSet < string >
1116
+ {
1117
+ "PII"
1118
+ } , new Dictionary < string , string >
1119
+ {
1120
+ [ "encrypt.kek.name" ] = "kek1" ,
1121
+ [ "encrypt.kms.type" ] = "local-kms" ,
1122
+ [ "encrypt.kms.key.id" ] = "mykey" ,
1123
+ [ "encrypt.dek.expiry.days" ] = "1"
1124
+ } )
1125
+ }
1126
+ ) ;
1127
+ store [ schemaStr ] = 1 ;
1128
+ subjectStore [ "topic-value" ] = new List < RegisteredSchema > { schema } ;
1129
+ var config = new AvroDeserializerConfig
1130
+ {
1131
+ } ;
1132
+ config . Set ( "rules.secret" , "mysecret" ) ;
1133
+ IRuleExecutor ruleExecutor = new FieldEncryptionExecutor ( dekRegistryClient , clock ) ;
1134
+ var deserializer = new AvroDeserializer < GenericRecord > ( schemaRegistryClient , config , new List < IRuleExecutor > { ruleExecutor } ) ;
1135
+
1136
+ kekStore [ new KekId ( "kek1" , false ) ] =
1137
+ new RegisteredKek ( )
1138
+ {
1139
+ Name = "kek1" ,
1140
+ KmsType = "local-kms" ,
1141
+ KmsKeyId = "mykey" ,
1142
+ } ;
1143
+ dekStore [ new DekId ( "kek1" , "topic-value" , 1 , DekFormat . AES256_GCM , false ) ] =
1144
+ new RegisteredDek ( )
1145
+ {
1146
+ Subject = "topic-value" ,
1147
+ Version = 1 ,
1148
+ Algorithm = DekFormat . AES256_GCM ,
1149
+ EncryptedKeyMaterial =
1150
+ "W/v6hOQYq1idVAcs1pPWz9UUONMVZW4IrglTnG88TsWjeCjxmtRQ4VaNe/I5dCfm2zyY9Cu0nqdvqImtUk4=" ,
1151
+ } ;
1152
+ Headers headers = new Headers ( ) ;
1153
+ byte [ ] bytes = new byte [ ] { 0 , 0 , 0 , 0 , 1 , 120 , 65 , 65 , 65 , 65 , 65 , 65 , 71 , 52 , 72 , 73 , 54 , 98 , 49 , 110 , 88 , 80 , 88 , 113 , 76 , 121 , 71 , 56 , 99 , 73 , 73 , 51 , 53 , 78 , 72 , 81 , 115 , 101 , 113 , 113 , 85 , 67 , 100 , 43 , 73 , 101 , 76 , 101 , 70 , 86 , 65 , 101 , 78 , 112 , 83 , 83 , 51 , 102 , 120 , 80 , 110 , 74 , 51 , 50 , 65 , 61 } ;
1154
+ var result = deserializer . DeserializeAsync ( bytes , false , new SerializationContext ( MessageComponentType . Value , testTopic , headers ) ) . Result ;
1155
+
1156
+ Assert . Equal ( "hello world" , result [ "f1" ] ) ;
1157
+ }
1158
+
980
1159
[ Fact ]
981
1160
public void GenericRecordJSONataFullyCompatible ( )
982
1161
{
0 commit comments