• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
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 com.android.adservices.service.adselection;
18 
19 import android.adservices.adselection.AuctionEncryptionKeyFixture;
20 import android.adservices.adselection.GetAdSelectionDataResponse;
21 
22 import com.android.adservices.ohttp.ObliviousHttpGateway;
23 import com.android.adservices.ohttp.OhttpGatewayPrivateKey;
24 import com.android.adservices.ohttp.algorithms.UnsupportedHpkeAlgorithmException;
25 import com.android.adservices.service.common.httpclient.AdServicesHttpClientResponse;
26 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers;
27 import com.android.adservices.service.stats.AdServicesLogger;
28 
29 import com.google.common.collect.ImmutableList;
30 import com.google.common.io.BaseEncoding;
31 import com.google.protobuf.ByteString;
32 
33 import org.json.JSONException;
34 
35 import java.io.IOException;
36 import java.util.HashMap;
37 import java.util.Map;
38 import java.util.Objects;
39 
40 /**
41  * Helper class for testing server auction. Primarily does server side decryption of
42  * getAdSelectionData response, server side encryption of AuctionResult which can then be decrypted
43  * by the client via persistAdSelectionResult and a few other utility methods.
44  */
45 public class ServerAuctionTestHelper {
46 
47     private static final String DEFAULT_PRIVATE_KEY_HEX =
48             "e7b292f49df28b8065992cdeadbc9d032a0e09e8476cb6d8d507212e7be3b9b4";
49     private static final String DEFAULT_PUBLIC_KEY_HEX =
50             "87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=";
51     private static final String DEFAULT_KEY_ID_HEX = "400bed24-c62f-46e0-a1ad-211361ad771a";
52     private static final int DEFAULT_COMPRESSION_ALGORITHM_VERSION = 2;
53     private static final int DEFAULT_PAYLOAD_FORMAT_VERSION = 0;
54     private static final ImmutableList<Integer> DEFAULT_PAYLOAD_BUCKET_SIZES =
55             ImmutableList.of(0, 1024, 2048, 4096, 8192, 16384, 32768, 65536);
56 
57     private final OhttpGatewayPrivateKey mPrivateKey;
58     public final AuctionEncryptionKeyFixture.AuctionKey mAuctionKey;
59     private final AuctionServerDataCompressor mAuctionServerDataCompressor;
60     private final AuctionServerPayloadFormatter mAuctionServerPayloadFormatter;
61     private final AuctionServerPayloadExtractor mAuctionServerPayloadExtractor;
62 
63     /**
64      * Gets an instance of the helper with default public/private key pair and default compressor
65      * and payload formatter versions
66      */
getDefaultInstance(AdServicesLogger adServicesLogger)67     public static ServerAuctionTestHelper getDefaultInstance(AdServicesLogger adServicesLogger) {
68         return new ServerAuctionTestHelper(
69                 DEFAULT_KEY_ID_HEX,
70                 DEFAULT_PRIVATE_KEY_HEX,
71                 DEFAULT_PUBLIC_KEY_HEX,
72                 DEFAULT_PAYLOAD_BUCKET_SIZES,
73                 DEFAULT_PAYLOAD_FORMAT_VERSION,
74                 DEFAULT_COMPRESSION_ALGORITHM_VERSION,
75                 adServicesLogger);
76     }
77 
ServerAuctionTestHelper( String idHex, String privateKeyHex, String publicKeyHex, ImmutableList<Integer> payloadBucketSizes, int payloadFormatterVersion, int compressorVersion, AdServicesLogger adServicesLogger)78     public ServerAuctionTestHelper(
79             String idHex,
80             String privateKeyHex,
81             String publicKeyHex,
82             ImmutableList<Integer> payloadBucketSizes,
83             int payloadFormatterVersion,
84             int compressorVersion,
85             AdServicesLogger adServicesLogger) {
86         mPrivateKey =
87                 OhttpGatewayPrivateKey.create(
88                         BaseEncoding.base16().lowerCase().decode(privateKeyHex));
89         mAuctionKey =
90                 AuctionEncryptionKeyFixture.AuctionKey.builder()
91                         .setKeyId(idHex)
92                         .setPublicKey(publicKeyHex)
93                         .build();
94         mAuctionServerDataCompressor =
95                 AuctionServerDataCompressorFactory.getDataCompressor(compressorVersion);
96         mAuctionServerPayloadFormatter =
97                 AuctionServerPayloadFormatterFactory.createPayloadFormatter(
98                         payloadFormatterVersion,
99                         payloadBucketSizes,
100                         /* sellerConfiguration= */ null);
101         mAuctionServerPayloadExtractor =
102                 AuctionServerPayloadFormatterFactory.createPayloadExtractor(
103                         payloadFormatterVersion, adServicesLogger);
104     }
105 
106     /** Get an HTTP response with the public auction key */
getPublicAuctionKeyHttpResponse()107     public AdServicesHttpClientResponse getPublicAuctionKeyHttpResponse() throws JSONException {
108         return AuctionEncryptionKeyFixture.mockAuctionKeyFetchResponseWithGivenKey(mAuctionKey);
109     }
110 
111     /** Get a map of decompressed buyer inputs from a protected auction input */
getDecompressedBuyerInputs( BiddingAuctionServers.ProtectedAuctionInput protectedAuctionInput)112     public Map<String, BiddingAuctionServers.BuyerInput> getDecompressedBuyerInputs(
113             BiddingAuctionServers.ProtectedAuctionInput protectedAuctionInput) throws Exception {
114         Map<String, BiddingAuctionServers.BuyerInput> decompressedBuyerInputs = new HashMap<>();
115         for (Map.Entry<String, ByteString> entry :
116                 protectedAuctionInput.getBuyerInputMap().entrySet()) {
117             byte[] buyerInputBytes = entry.getValue().toByteArray();
118             byte[] decompressed =
119                     mAuctionServerDataCompressor
120                             .decompress(
121                                     AuctionServerDataCompressor.CompressedData.create(
122                                             buyerInputBytes))
123                             .getData();
124             decompressedBuyerInputs.put(
125                     entry.getKey(), BiddingAuctionServers.BuyerInput.parseFrom(decompressed));
126         }
127         return decompressedBuyerInputs;
128     }
129 
130     /** Get a protected auction input from the encrypted ad selection data */
decryptAdSelectionData( byte[] adSelectionData)131     public BiddingAuctionServers.ProtectedAuctionInput decryptAdSelectionData(
132             byte[] adSelectionData) throws Exception {
133         byte[] decrypted =
134                 ObliviousHttpGateway.decrypt(mPrivateKey, Objects.requireNonNull(adSelectionData));
135         AuctionServerPayloadUnformattedData unformatted =
136                 mAuctionServerPayloadExtractor.extract(
137                         AuctionServerPayloadFormattedData.create(decrypted));
138         return BiddingAuctionServers.ProtectedAuctionInput.parseFrom(unformatted.getData());
139     }
140 
141     /**
142      * Returns an encrypted server response based on the output of getAdSelectionData() and
143      * unencrypted auction result bytes
144      */
encryptServerAuctionResult( GetAdSelectionDataResponse adSelectionData, BiddingAuctionServers.AuctionResult auctionResult)145     public byte[] encryptServerAuctionResult(
146             GetAdSelectionDataResponse adSelectionData,
147             BiddingAuctionServers.AuctionResult auctionResult)
148             throws UnsupportedHpkeAlgorithmException, IOException {
149         return ObliviousHttpGateway.encrypt(
150                 mPrivateKey,
151                 Objects.requireNonNull(adSelectionData.getAdSelectionData()),
152                 prepareAuctionResultBytes(auctionResult));
153     }
154 
prepareAuctionResultBytes(BiddingAuctionServers.AuctionResult auctionResult)155     private byte[] prepareAuctionResultBytes(BiddingAuctionServers.AuctionResult auctionResult) {
156         byte[] auctionResultBytes = auctionResult.toByteArray();
157         AuctionServerDataCompressor.CompressedData compressedData =
158                 mAuctionServerDataCompressor.compress(
159                         AuctionServerDataCompressor.UncompressedData.create(auctionResultBytes));
160         AuctionServerPayloadFormattedData formattedData =
161                 mAuctionServerPayloadFormatter.apply(
162                         AuctionServerPayloadUnformattedData.create(compressedData.getData()),
163                         AuctionServerDataCompressorGzip.VERSION);
164         return formattedData.getData();
165     }
166 }
167