Skip to content

Commit a79934b

Browse files
[DLP] Deidentify table with two separate cryptographic hash transformations (GoogleCloudPlatform#7980)
* implemented DeIdentifyTableWithMultipleCryptoHash.java * added testcase and resolved linting error * refactored the code * resolved the review comments * modified the comment
1 parent 25464b9 commit a79934b

2 files changed

Lines changed: 243 additions & 5 deletions

File tree

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package dlp.snippets;
18+
19+
// [START dlp_deidentify_table_with_multiple_crypto_hash]
20+
21+
import com.google.cloud.dlp.v2.DlpServiceClient;
22+
import com.google.privacy.dlp.v2.ContentItem;
23+
import com.google.privacy.dlp.v2.CryptoHashConfig;
24+
import com.google.privacy.dlp.v2.CryptoKey;
25+
import com.google.privacy.dlp.v2.DeidentifyConfig;
26+
import com.google.privacy.dlp.v2.DeidentifyContentRequest;
27+
import com.google.privacy.dlp.v2.DeidentifyContentResponse;
28+
import com.google.privacy.dlp.v2.FieldId;
29+
import com.google.privacy.dlp.v2.FieldTransformation;
30+
import com.google.privacy.dlp.v2.InfoType;
31+
import com.google.privacy.dlp.v2.InfoTypeTransformations;
32+
import com.google.privacy.dlp.v2.InspectConfig;
33+
import com.google.privacy.dlp.v2.LocationName;
34+
import com.google.privacy.dlp.v2.PrimitiveTransformation;
35+
import com.google.privacy.dlp.v2.RecordTransformations;
36+
import com.google.privacy.dlp.v2.Table;
37+
import com.google.privacy.dlp.v2.TransientCryptoKey;
38+
import com.google.privacy.dlp.v2.Value;
39+
import java.io.IOException;
40+
import java.util.ArrayList;
41+
import java.util.List;
42+
import java.util.stream.Collectors;
43+
import java.util.stream.Stream;
44+
45+
public class DeIdentifyTableWithMultipleCryptoHash {
46+
47+
public static void main(String[] args) throws Exception {
48+
// TODO(developer): Replace these variables before running the sample.
49+
50+
// The Google Cloud project id to use as a parent resource.
51+
String projectId = "your-project-id";
52+
53+
// The table to de-identify.
54+
Table tableToDeIdentify =
55+
Table.newBuilder()
56+
.addHeaders(FieldId.newBuilder().setName("userid").build())
57+
.addHeaders(FieldId.newBuilder().setName("comments").build())
58+
.addRows(
59+
Table.Row.newBuilder()
60+
.addValues(Value.newBuilder().setStringValue("user1@example.org").build())
61+
.addValues(
62+
Value.newBuilder()
63+
.setStringValue(
64+
"my email is user1@example.org and phone is 858-555-0222")
65+
.build())
66+
.build())
67+
.addRows(
68+
Table.Row.newBuilder()
69+
.addValues(Value.newBuilder().setStringValue("user2@example.org").build())
70+
.addValues(
71+
Value.newBuilder()
72+
.setStringValue(
73+
"my email is user2@example.org and phone is 858-555-0223")
74+
.build())
75+
.build())
76+
.addRows(
77+
Table.Row.newBuilder()
78+
.addValues(Value.newBuilder().setStringValue("user3@example.org").build())
79+
.addValues(
80+
Value.newBuilder()
81+
.setStringValue(
82+
"my email is user3@example.org and phone is 858-555-0224")
83+
.build())
84+
.build())
85+
.build();
86+
87+
// The names of the keys used to encrypt the data.
88+
String transientKeyName1 = "YOUR_TRANSIENT_CRYPTO_KEY";
89+
String transientKeyName2 = "YOUR_TRANSIENT_CRYPTO_KEY_2";
90+
91+
deIdentifyWithCryptHashTransformation(
92+
projectId, tableToDeIdentify, transientKeyName1, transientKeyName2);
93+
}
94+
95+
// Transforms findings using two separate cryptographic hash transformations.
96+
public static void deIdentifyWithCryptHashTransformation(
97+
String projectId, Table tableToDeIdentify, String transientKeyName1, String transientKeyName2)
98+
throws IOException {
99+
// Initialize client that will be used to send requests. This client only needs to be created
100+
// once, and can be reused for multiple requests. After completing all of your requests, call
101+
// the "close" method on the client to safely clean up any remaining background resources.
102+
try (DlpServiceClient dlp = DlpServiceClient.create()) {
103+
// Specify what content you want the service to DeIdentify
104+
ContentItem contentItem = ContentItem.newBuilder().setTable(tableToDeIdentify).build();
105+
106+
// Specify the type of info the inspection will look for.
107+
// See https://cloud.google.com/dlp/docs/infotypes-reference for complete list of info types
108+
List<InfoType> infoTypes =
109+
Stream.of("PHONE_NUMBER", "EMAIL_ADDRESS")
110+
.map(it -> InfoType.newBuilder().setName(it).build())
111+
.collect(Collectors.toList());
112+
113+
InspectConfig inspectConfig = InspectConfig.newBuilder()
114+
.addAllInfoTypes(infoTypes)
115+
.build();
116+
117+
// Specify the transient key which will encrypt the data.
118+
TransientCryptoKey transientCryptoKey = TransientCryptoKey.newBuilder()
119+
.setName(transientKeyName1)
120+
.build();
121+
TransientCryptoKey transientCryptoKey2 = TransientCryptoKey.newBuilder()
122+
.setName(transientKeyName2)
123+
.build();
124+
125+
CryptoKey cryptoKey = CryptoKey.newBuilder()
126+
.setTransient(transientCryptoKey)
127+
.build();
128+
129+
CryptoKey cryptoKey2 = CryptoKey.newBuilder()
130+
.setTransient(transientCryptoKey2)
131+
.build();
132+
133+
CryptoHashConfig cryptoHashConfig = CryptoHashConfig.newBuilder()
134+
.setCryptoKey(cryptoKey)
135+
.build();
136+
137+
CryptoHashConfig cryptoHashConfig2 = CryptoHashConfig.newBuilder()
138+
.setCryptoKey(cryptoKey2)
139+
.build();
140+
141+
// Define type of de-identification as cryptographic hash transformation.
142+
PrimitiveTransformation primitiveTransformation = PrimitiveTransformation.newBuilder()
143+
.setCryptoHashConfig(cryptoHashConfig)
144+
.build();
145+
146+
PrimitiveTransformation primitiveTransformation2 = PrimitiveTransformation.newBuilder()
147+
.setCryptoHashConfig(cryptoHashConfig2)
148+
.build();
149+
150+
InfoTypeTransformations.InfoTypeTransformation infoTypeTransformation =
151+
InfoTypeTransformations.InfoTypeTransformation.newBuilder()
152+
.setPrimitiveTransformation(primitiveTransformation2)
153+
.addAllInfoTypes(infoTypes)
154+
.build();
155+
156+
InfoTypeTransformations transformations =
157+
InfoTypeTransformations.newBuilder().addTransformations(infoTypeTransformation).build();
158+
159+
// Specify fields to be de-identified.
160+
List<FieldId> fieldIds =
161+
Stream.of("userid")
162+
.map(id -> FieldId.newBuilder().setName(id).build())
163+
.collect(Collectors.toList());
164+
165+
List<FieldId> fieldIds1 =
166+
Stream.of("comments")
167+
.map(id -> FieldId.newBuilder().setName(id).build())
168+
.collect(Collectors.toList());
169+
170+
List<FieldTransformation> fieldTransformations = new ArrayList<>();
171+
fieldTransformations.add(
172+
FieldTransformation.newBuilder()
173+
.addAllFields(fieldIds)
174+
.setPrimitiveTransformation(primitiveTransformation)
175+
.build());
176+
fieldTransformations.add(
177+
FieldTransformation.newBuilder()
178+
.addAllFields(fieldIds1)
179+
.setInfoTypeTransformations(transformations)
180+
.build());
181+
182+
RecordTransformations recordTransformations = RecordTransformations.newBuilder()
183+
.addAllFieldTransformations(fieldTransformations)
184+
.build();
185+
186+
// Specify the config for the de-identify request
187+
DeidentifyConfig deidentifyConfig = DeidentifyConfig.newBuilder()
188+
.setRecordTransformations(recordTransformations)
189+
.build();
190+
191+
// Combine configurations into a request for the service.
192+
DeidentifyContentRequest request =
193+
DeidentifyContentRequest.newBuilder()
194+
.setParent(LocationName.of(projectId, "global").toString())
195+
.setItem(contentItem)
196+
.setInspectConfig(inspectConfig)
197+
.setDeidentifyConfig(deidentifyConfig)
198+
.build();
199+
200+
// Send the request and receive response from the service.
201+
DeidentifyContentResponse response = dlp.deidentifyContent(request);
202+
203+
// Print the results.
204+
System.out.println("Table after de-identification: " + response.getItem().getTable());
205+
}
206+
}
207+
}
208+
209+
// [END dlp_deidentify_table_with_multiple_crypto_hash]

‎dlp/snippets/src/test/java/dlp/snippets/DeIdentificationTests.java‎

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ public void testReIdentifyWithDeterministicEncryption() throws IOException {
566566
String output = bout.toString();
567567
assertThat(output).contains("Text after re-identification: My SSN is 372819127");
568568
}
569-
569+
570570
@Test
571571
public void testDeIdentifyWithFpeSurrogate() throws IOException, NoSuchAlgorithmException {
572572

@@ -732,6 +732,36 @@ public void testDeIdentifyWithBucketingConfig() throws IOException {
732732
assertThat(output).contains("Table after de-identification: ");
733733
}
734734

735+
@Test
736+
public void testDeIdentifyTableWithMultipleCryptoHash() throws IOException {
737+
738+
Table tableToDeIdentify =
739+
Table.newBuilder()
740+
.addHeaders(FieldId.newBuilder().setName("userid").build())
741+
.addHeaders(FieldId.newBuilder().setName("comments").build())
742+
.addRows(
743+
Table.Row.newBuilder()
744+
.addValues(Value.newBuilder().setStringValue("user1@example.org").build())
745+
.addValues(
746+
Value.newBuilder()
747+
.setStringValue(
748+
"my email is user1@example.org and phone is 858-555-0222")
749+
.build())
750+
.build())
751+
.build();
752+
753+
// Transient keys are generated by DLP API for each request and used for hashing the data.
754+
String transientKeyName1 = "TransientKeyName1";
755+
String transientKeyName2 = "TransientKeyName2";
756+
757+
DeIdentifyTableWithMultipleCryptoHash.deIdentifyWithCryptHashTransformation(
758+
PROJECT_ID, tableToDeIdentify, transientKeyName1, transientKeyName2);
759+
String output = bout.toString();
760+
assertThat(output).contains("Table after de-identification: ");
761+
assertThat(output).doesNotContain("user1@example.org");
762+
assertThat(output).doesNotContain("858-555-0222");
763+
}
764+
735765
@Test
736766
public void testDeIdentifyTableWithCryptoHash() throws IOException {
737767

@@ -750,12 +780,11 @@ public void testDeIdentifyTableWithCryptoHash() throws IOException {
750780
.build())
751781
.build();
752782

753-
// Generate a random string to use it as Transient CryptoKey.
754-
UUID uuid = UUID.randomUUID();
755-
String randomString = uuid.toString().replace("-", "");
783+
// Transient key is generated by DLP API for each request and used for hashing the data.
784+
String transientKeyName = "TransientKeyName";
756785

757786
DeIdentifyTableWithCryptoHash.deIdentifyWithCryptHashTransformation(
758-
PROJECT_ID, tableToDeIdentify, randomString);
787+
PROJECT_ID, tableToDeIdentify, transientKeyName);
759788
String output = bout.toString();
760789
assertThat(output).contains("Table after de-identification: ");
761790
assertThat(output).doesNotContain("user1@example.org");

0 commit comments

Comments
 (0)