1 /*
2  * Copyright (C) 2020 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 android.car.encryptionrunner;
18 
19 import android.annotation.NonNull;
20 
21 /**
22  * A generalized interface that allows for generating shared secrets as well as encrypting
23  * messages.
24  *
25  * To use this interface:
26  *
27  * <p>1. As a client.
28  *
29  * {@code
30  * HandshakeMessage initialClientMessage = clientRunner.initHandshake();
31  * sendToServer(initialClientMessage.getNextMessage());
32  * byte message = getServerResponse();
33  * HandshakeMessage message = clientRunner.continueHandshake(message);
34  * }
35  *
36  * <p>If it is a first-time connection,
37  *
38  * {@code message.getHandshakeState()} should be VERIFICATION_NEEDED, show user the verification
39  * code and ask to verify.
40  * After user confirmed, {@code HandshakeMessage lastMessage = clientRunner.verifyPin();} otherwise
41  * {@code clientRunner.invalidPin(); }
42  *
43  * Use {@code lastMessage.getKey()} to get the key for encryption.
44  *
45  * <p>If it is a reconnection,
46  *
47  * {@code message.getHandshakeState()} should be RESUMING_SESSION, PIN has been verified blindly,
48  * send the authentication message over to server, then authenticate the message from server.
49  *
50  * {@code
51  * clientMessage = clientRunner.initReconnectAuthentication(previousKey)
52  * sendToServer(clientMessage.getNextMessage());
53  * HandshakeMessage lastMessage = clientRunner.authenticateReconnection(previousKey, message)
54  * }
55  *
56  * {@code lastMessage.getHandshakeState()} should be FINISHED if reconnection handshake is done.
57  *
58  * <p>2. As a server.
59  *
60  * {@code
61  * byte[] initialMessage = getClientMessageBytes();
62  * HandshakeMessage message = serverRunner.respondToInitRequest(initialMessage);
63  * sendToClient(message.getNextMessage());
64  * byte[] clientMessage = getClientResponse();
65  * HandshakeMessage message = serverRunner.continueHandshake(clientMessage);}
66  *
67  * <p>if it is a first-time connection,
68  *
69  * {@code message.getHandshakeState()} should be VERIFICATION_NEEDED, show user the verification
70  * code and ask to verify.
71  * After PIN is confirmed, {@code HandshakeMessage lastMessage = serverRunner.verifyPin}, otherwise
72  * {@code clientRunner.invalidPin(); }
73  * Use {@code lastMessage.getKey()} to get the key for encryption.
74  *
75  * <p>If it is a reconnection,
76  *
77  * {@code message.getHandshakeState()} should be RESUMING_SESSION,PIN has been verified blindly,
78  * waiting for client message.
79  * After client message been received,
80  * {@code serverMessage = serverRunner.authenticateReconnection(previousKey, message);
81  * sendToClient(serverMessage.getNextMessage());}
82  * {@code serverMessage.getHandshakeState()} should be FINISHED if reconnection handshake is done.
83  *
84  * Also see {@link EncryptionRunnerTest} for examples.
85  */
86 public interface EncryptionRunner {
87 
88     String TAG = "EncryptionRunner";
89 
90     /**
91      * Starts an encryption handshake.
92      *
93      * @return A handshake message with information about the handshake that is started.
94      */
95     @NonNull
initHandshake()96     HandshakeMessage initHandshake();
97 
98     /**
99      * Starts an encryption handshake where the device that is being communicated with already
100      * initiated the request.
101      *
102      * @param initializationRequest the bytes that the other device sent over.
103      * @return a handshake message with information about the handshake.
104      * @throws HandshakeException if initialization request is invalid.
105      */
106     @NonNull
respondToInitRequest(@onNull byte[] initializationRequest)107     HandshakeMessage respondToInitRequest(@NonNull byte[] initializationRequest)
108             throws HandshakeException;
109 
110     /**
111      * Continues a handshake after receiving another response from the connected device.
112      *
113      * @param response the response from the other device.
114      * @return a message that can be used to continue the handshake.
115      * @throws HandshakeException if unexpected bytes in response.
116      */
117     @NonNull
continueHandshake(@onNull byte[] response)118     HandshakeMessage continueHandshake(@NonNull byte[] response) throws HandshakeException;
119 
120     /**
121      * Verifies the pin shown to the user. The result is the next handshake message and will
122      * typically contain an encryption key.
123      *
124      * @throws HandshakeException if not in state to verify pin.
125      */
126     @NonNull
verifyPin()127     HandshakeMessage verifyPin() throws HandshakeException;
128 
129     /**
130      * Notifies the encryption runner that the user failed to validate the pin. After calling this
131      * method the runner should not be used, and will throw exceptions.
132      */
invalidPin()133     void invalidPin();
134 
135     /**
136      * Verifies the reconnection message.
137      *
138      * <p>The message passed to this method should have been generated by
139      * {@link #initReconnectAuthentication(byte[] previousKey)}.
140      *
141      * <p>If the message is valid, then a {@link HandshakeMessage} will be returned that contains
142      * the encryption key and a handshake message which can be used to verify the other side of the
143      * connection.
144      *
145      * @param previousKey previously stored key.
146      * @param message     message from the client
147      * @return a handshake message with an encryption key if verification succeed.
148      * @throws HandshakeException if the message does not match.
149      */
150     @NonNull
authenticateReconnection(@onNull byte[] message, @NonNull byte[] previousKey)151     HandshakeMessage authenticateReconnection(@NonNull byte[] message, @NonNull byte[] previousKey)
152             throws HandshakeException;
153 
154     /**
155      * Initiates the reconnection verification by generating a message that should be sent to the
156      * device that is being reconnected to.
157      *
158      * @param previousKey previously stored key.
159      * @return a handshake message with client's message which will be sent to server.
160      * @throws HandshakeException when get encryption key's unique session fail.
161      */
162     @NonNull
initReconnectAuthentication(@onNull byte[] previousKey)163     HandshakeMessage initReconnectAuthentication(@NonNull byte[] previousKey)
164             throws HandshakeException;
165 
166     /**
167      * De-serializes a previously serialized key generated by an instance of this encryption runner.
168      *
169      * @param serialized the serialized bytes of the key.
170      * @return the Key object used for encryption.
171      */
172     @NonNull
keyOf(@onNull byte[] serialized)173     Key keyOf(@NonNull byte[] serialized);
174 
175     /**
176      * Set the signal if it is a reconnection process.
177      *
178      * @param isReconnect {@code true} if it is a reconnect.
179      */
setIsReconnect(boolean isReconnect)180     void setIsReconnect(boolean isReconnect);
181 }
182