summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Subv2017-06-14 12:47:52 -0500
committerGravatar Subv2017-06-26 12:24:09 -0500
commit9befb8c887b78128a2e8ef8febc82a4933196602 (patch)
treed4e208d9d250af677166ebdedc29e4595a22d8a8 /src
parentUDS: Clarify comment about the first 4 bytes of the SecureData header. (diff)
downloadyuzu-9befb8c887b78128a2e8ef8febc82a4933196602.tar.gz
yuzu-9befb8c887b78128a2e8ef8febc82a4933196602.tar.xz
yuzu-9befb8c887b78128a2e8ef8febc82a4933196602.zip
UDS: Added functions to encrypt and decrypt the data frames.
The responsibility of encryption and encapsulation into an 802.11 MAC frame will fall into the callers of GenerateDataPayload.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nwm/nwm_uds.cpp9
-rw-r--r--src/core/hle/service/nwm/uds_data.cpp148
-rw-r--r--src/core/hle/service/nwm/uds_data.h11
3 files changed, 156 insertions, 12 deletions
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index c43c5ca44..d9bd9c4a4 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -433,9 +433,12 @@ static void SendTo(Interface* self) {
433 433
434 // TODO(Subv): Increment the sequence number after each sent packet. 434 // TODO(Subv): Increment the sequence number after each sent packet.
435 u16 sequence_number = 0; 435 u16 sequence_number = 0;
436 std::vector<u8> data_frame = GenerateDataFrame(data, data_channel, dest_node_id, 436 std::vector<u8> data_payload = GenerateDataPayload(data, data_channel, dest_node_id,
437 connection_status.network_node_id, 437 connection_status.network_node_id,
438 sequence_number); 438 sequence_number);
439
440 // TODO(Subv): Retrieve the MAC address of the dest_node_id and our own to encrypt
441 // and encapsulate the payload.
439 442
440 // TODO(Subv): Send the frame. 443 // TODO(Subv): Send the frame.
441 444
diff --git a/src/core/hle/service/nwm/uds_data.cpp b/src/core/hle/service/nwm/uds_data.cpp
index 9ba2fdcf1..e05ca8815 100644
--- a/src/core/hle/service/nwm/uds_data.cpp
+++ b/src/core/hle/service/nwm/uds_data.cpp
@@ -5,10 +5,12 @@
5#include <cstring> 5#include <cstring>
6 6
7#include "core/hle/service/nwm/nwm_uds.h" 7#include "core/hle/service/nwm/nwm_uds.h"
8#include "core/hle/service/nwm/uds_beacon.h"
8#include "core/hle/service/nwm/uds_data.h" 9#include "core/hle/service/nwm/uds_data.h"
9#include "core/hw/aes/key.h" 10#include "core/hw/aes/key.h"
10 11
11#include <cryptopp/aes.h> 12#include <cryptopp/ccm.h>
13#include <cryptopp/filters.h>
12#include <cryptopp/md5.h> 14#include <cryptopp/md5.h>
13#include <cryptopp/modes.h> 15#include <cryptopp/modes.h>
14 16
@@ -98,15 +100,149 @@ static std::array<u8, CryptoPP::AES::BLOCKSIZE> GenerateDataCCMPKey(const std::v
98 return ccmp_key; 100 return ccmp_key;
99} 101}
100 102
101std::vector<u8> GenerateDataFrame(const std::vector<u8>& data, u8 channel, u16 dest_node, u16 src_node, u16 sequence_number) { 103/*
104 * Generates the Additional Authenticated Data (AAD) for an UDS 802.11 encrypted data frame.
105 * @returns a buffer with the bytes of the AAD.
106 */
107static std::vector<u8> GenerateCCMPAAD(const MacAddress& sender, const MacAddress& receiver) {
108 // Reference: IEEE 802.11-2007
109
110 // 8.3.3.3.2 Construct AAD (22-30 bytes)
111 // The AAD is constructed from the MPDU header. The AAD does not include the header Duration
112 // field, because the Duration field value can change due to normal IEEE 802.11 operation (e.g.,
113 // a rate change during retransmission). For similar reasons, several subfields in the Frame
114 // Control field are masked to 0.
115 struct {
116 u16_be FC; // MPDU Frame Control field
117 MacAddress receiver;
118 MacAddress transmitter;
119 MacAddress destination;
120 u16_be SC; // MPDU Sequence Control field
121 } aad_struct{};
122
123 // Default FC value of DataFrame | Protected | ToDS
124 constexpr u16 DefaultFrameControl = 0x0841;
125
126 aad_struct.FC = DefaultFrameControl;
127 aad_struct.SC = 0;
128 aad_struct.transmitter = sender;
129 aad_struct.receiver = receiver;
130 aad_struct.destination = receiver;
131
132 std::vector<u8> aad(sizeof(aad_struct));
133 std::memcpy(aad.data(), &aad_struct, sizeof(aad_struct));
134
135 return aad;
136}
137
138/*
139 * Decrypts the payload of an encrypted 802.11 data frame using the specified key.
140 * @returns The decrypted payload.
141 */
142static std::vector<u8> DecryptDataFrame(const std::vector<u8>& encrypted_payload, const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key,
143 const MacAddress& sender, const MacAddress& receiver, u16 sequence_number) {
144
145 // Reference: IEEE 802.11-2007
146
147 std::vector<u8> aad = GenerateCCMPAAD(sender, receiver);
148
149 std::vector<u8> packet_number{0, 0, 0, 0,
150 static_cast<u8>((sequence_number >> 8) & 0xFF),
151 static_cast<u8>(sequence_number & 0xFF)};
152
153 // 8.3.3.3.3 Construct CCM nonce (13 bytes)
154 std::vector<u8> nonce;
155 nonce.push_back(0); // priority
156 nonce.insert(nonce.end(), sender.begin(), sender.end()); // Address 2
157 nonce.insert(nonce.end(), packet_number.begin(), packet_number.end()); // PN
158
159 try {
160 CryptoPP::CCM<CryptoPP::AES, 8>::Decryption d;
161 d.SetKeyWithIV(ccmp_key.data(), ccmp_key.size(), nonce.data(), nonce.size());
162 d.SpecifyDataLengths(aad.size(), encrypted_payload.size() - 8, 0);
163
164 CryptoPP::AuthenticatedDecryptionFilter df(d, nullptr,
165 CryptoPP::AuthenticatedDecryptionFilter::MAC_AT_END |
166 CryptoPP::AuthenticatedDecryptionFilter::THROW_EXCEPTION);
167 // put aad
168 df.ChannelPut(CryptoPP::AAD_CHANNEL, aad.data(), aad.size());
169
170 // put cipher with mac
171 df.ChannelPut(CryptoPP::DEFAULT_CHANNEL, encrypted_payload.data(), encrypted_payload.size() - 8);
172 df.ChannelPut(CryptoPP::DEFAULT_CHANNEL, encrypted_payload.data() + encrypted_payload.size() - 8, 8);
173
174 df.ChannelMessageEnd(CryptoPP::AAD_CHANNEL);
175 df.ChannelMessageEnd(CryptoPP::DEFAULT_CHANNEL);
176 df.SetRetrievalChannel(CryptoPP::DEFAULT_CHANNEL);
177
178 int size = df.MaxRetrievable();
179
180 std::vector<u8> pdata(size);
181 df.Get(pdata.data(), size);
182 return pdata;
183 } catch (CryptoPP::Exception&) {
184 LOG_ERROR(Service_NWM, "failed to decrypt");
185 }
186
187 return {};
188}
189
190/*
191 * Encrypts the payload of an 802.11 data frame using the specified key.
192 * @returns The encrypted payload.
193 */
194static std::vector<u8> EncryptDataFrame(const std::vector<u8>& payload, const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key,
195 const MacAddress& sender, const MacAddress& receiver, u16 sequence_number) {
196 // Reference: IEEE 802.11-2007
197
198 std::vector<u8> aad = GenerateCCMPAAD(sender, receiver);
199
200 std::vector<u8> packet_number{0, 0, 0, 0,
201 static_cast<u8>((sequence_number >> 8) & 0xFF),
202 static_cast<u8>(sequence_number & 0xFF)};
203
204 // 8.3.3.3.3 Construct CCM nonce (13 bytes)
205 std::vector<u8> nonce;
206 nonce.push_back(0); // priority
207 nonce.insert(nonce.end(), sender.begin(), sender.end()); // Address 2
208 nonce.insert(nonce.end(), packet_number.begin(), packet_number.end()); // PN
209
210 try {
211 CryptoPP::CCM<CryptoPP::AES, 8>::Encryption d;
212 d.SetKeyWithIV(ccmp_key.data(), ccmp_key.size(), nonce.data(), nonce.size());
213 d.SpecifyDataLengths(aad.size(), payload.size(), 0);
214
215 CryptoPP::AuthenticatedEncryptionFilter df(d);
216 // put aad
217 df.ChannelPut(CryptoPP::AAD_CHANNEL, aad.data(), aad.size());
218 df.ChannelMessageEnd(CryptoPP::AAD_CHANNEL);
219
220 // put plaintext
221 df.ChannelPut(CryptoPP::DEFAULT_CHANNEL, payload.data(), payload.size());
222 df.ChannelMessageEnd(CryptoPP::DEFAULT_CHANNEL);
223
224 df.SetRetrievalChannel(CryptoPP::DEFAULT_CHANNEL);
225
226 int size = df.MaxRetrievable();
227
228 std::vector<u8> cipher(size);
229 df.Get(cipher.data(), size);
230 return cipher;
231 } catch (CryptoPP::Exception&) {
232 LOG_ERROR(Service_NWM, "failed to encrypt");
233 }
234
235 return {};
236}
237
238std::vector<u8> GenerateDataPayload(const std::vector<u8>& data, u8 channel, u16 dest_node, u16 src_node,
239 u16 sequence_number) {
102 std::vector<u8> buffer = GenerateLLCHeader(EtherType::SecureData); 240 std::vector<u8> buffer = GenerateLLCHeader(EtherType::SecureData);
103 std::vector<u8> securedata_header = GenerateSecureDataHeader(data.size(), channel, dest_node, src_node, sequence_number); 241 std::vector<u8> securedata_header = GenerateSecureDataHeader(data.size(), channel, dest_node, src_node,
242 sequence_number);
104 243
105 buffer.insert(buffer.end(), securedata_header.begin(), securedata_header.end()); 244 buffer.insert(buffer.end(), securedata_header.begin(), securedata_header.end());
106 buffer.insert(buffer.end(), data.begin(), data.end()); 245 buffer.insert(buffer.end(), data.begin(), data.end());
107 // TODO(Subv): Encrypt the frame.
108 // TODO(Subv): Prepend CCMP initialization vector (sequence_number).
109 // TODO(Subv): Encapsulate the frame in an 802.11 data frame.
110 return buffer; 246 return buffer;
111} 247}
112 248
diff --git a/src/core/hle/service/nwm/uds_data.h b/src/core/hle/service/nwm/uds_data.h
index 8480ef94b..960f13cee 100644
--- a/src/core/hle/service/nwm/uds_data.h
+++ b/src/core/hle/service/nwm/uds_data.h
@@ -4,10 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <vector>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8#include "common/swap.h" 11#include "common/swap.h"
9#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
10 13
14#include <cryptopp/aes.h>
15
11namespace Service { 16namespace Service {
12namespace NWM { 17namespace NWM {
13 18
@@ -73,10 +78,10 @@ struct DataFrameCryptoCTR {
73static_assert(sizeof(DataFrameCryptoCTR) == 16, "DataFrameCryptoCTR has the wrong size"); 78static_assert(sizeof(DataFrameCryptoCTR) == 16, "DataFrameCryptoCTR has the wrong size");
74 79
75/** 80/**
76 * Generates an encrypted 802.11 data frame starting at the CCMP IV. 81 * Generates an unencrypted 802.11 data payload.
77 * @returns The generated frame. 82 * @returns The generated frame payload.
78 */ 83 */
79std::vector<u8> GenerateDataFrame(const std::vector<u8>& data, u8 channel, u16 dest_node, u16 src_node, u16 sequence_number); 84std::vector<u8> GenerateDataPayload(const std::vector<u8>& data, u8 channel, u16 dest_node, u16 src_node, u16 sequence_number);
80 85
81} // namespace NWM 86} // namespace NWM
82} // namespace Service 87} // namespace Service