summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar wwylele2017-01-01 14:58:24 +0200
committerGravatar wwylele2017-02-21 23:57:31 +0200
commitd5b0e275e3391a1449c77d2ee6ea0384706ebaaa (patch)
tree4266cba75c9298fd5733a22ede04e8e3b64aa9f0
parentHW: add AES engine & implement AES-CCM (diff)
downloadyuzu-d5b0e275e3391a1449c77d2ee6ea0384706ebaaa.tar.gz
yuzu-d5b0e275e3391a1449c77d2ee6ea0384706ebaaa.tar.xz
yuzu-d5b0e275e3391a1449c77d2ee6ea0384706ebaaa.zip
APT: implement Wrap and Unwrap
-rw-r--r--src/core/hle/service/apt/apt.cpp103
-rw-r--r--src/core/hle/service/apt/apt.h40
-rw-r--r--src/core/hle/service/apt/apt_a.cpp4
-rw-r--r--src/core/hle/service/apt/apt_s.cpp4
-rw-r--r--src/core/hle/service/apt/apt_u.cpp4
5 files changed, 149 insertions, 6 deletions
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 615fe31ea..e57b19c2d 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -18,6 +18,8 @@
18#include "core/hle/service/fs/archive.h" 18#include "core/hle/service/fs/archive.h"
19#include "core/hle/service/ptm/ptm.h" 19#include "core/hle/service/ptm/ptm.h"
20#include "core/hle/service/service.h" 20#include "core/hle/service/service.h"
21#include "core/hw/aes/ccm.h"
22#include "core/hw/aes/key.h"
21 23
22namespace Service { 24namespace Service {
23namespace APT { 25namespace APT {
@@ -470,6 +472,107 @@ void GetStartupArgument(Service::Interface* self) {
470 cmd_buff[2] = 0; 472 cmd_buff[2] = 0;
471} 473}
472 474
475void Wrap(Service::Interface* self) {
476 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x46, 4, 4);
477 const u32 output_size = rp.Pop<u32>();
478 const u32 input_size = rp.Pop<u32>();
479 const u32 nonce_offset = rp.Pop<u32>();
480 u32 nonce_size = rp.Pop<u32>();
481 size_t desc_size;
482 IPC::MappedBufferPermissions desc_permission;
483 const VAddr input = rp.PopMappedBuffer(&desc_size, &desc_permission);
484 ASSERT(desc_size == input_size && desc_permission == IPC::MappedBufferPermissions::R);
485 const VAddr output = rp.PopMappedBuffer(&desc_size, &desc_permission);
486 ASSERT(desc_size == output_size && desc_permission == IPC::MappedBufferPermissions::W);
487
488 // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't
489 // check the buffer size and writes data with potential overflow.
490 ASSERT_MSG(output_size == input_size + HW::AES::CCM_MAC_SIZE,
491 "input_size (%d) doesn't match to output_size (%d)", input_size, output_size);
492
493 LOG_DEBUG(Service_APT, "called, output_size=%u, input_size=%u, nonce_offset=%u, nonce_size=%u",
494 output_size, input_size, nonce_offset, nonce_size);
495
496 // Note: This weird nonce size modification is verified against real 3DS
497 nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE);
498
499 // Reads nonce and concatenates the rest of the input as plaintext
500 HW::AES::CCMNonce nonce{};
501 Memory::ReadBlock(input + nonce_offset, nonce.data(), nonce_size);
502 u32 pdata_size = input_size - nonce_size;
503 std::vector<u8> pdata(pdata_size);
504 Memory::ReadBlock(input, pdata.data(), nonce_offset);
505 Memory::ReadBlock(input + nonce_offset + nonce_size, pdata.data() + nonce_offset,
506 pdata_size - nonce_offset);
507
508 // Encrypts the plaintext using AES-CCM
509 auto cipher = HW::AES::EncryptSignCCM(pdata, nonce, HW::AES::KeySlotID::APTWrap);
510
511 // Puts the nonce to the beginning of the output, with ciphertext followed
512 Memory::WriteBlock(output, nonce.data(), nonce_size);
513 Memory::WriteBlock(output + nonce_size, cipher.data(), cipher.size());
514
515 IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
516 rb.Push(RESULT_SUCCESS);
517
518 // Unmap buffer
519 rb.PushMappedBuffer(input, input_size, IPC::MappedBufferPermissions::R);
520 rb.PushMappedBuffer(output, output_size, IPC::MappedBufferPermissions::W);
521}
522
523void Unwrap(Service::Interface* self) {
524 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x47, 4, 4);
525 const u32 output_size = rp.Pop<u32>();
526 const u32 input_size = rp.Pop<u32>();
527 const u32 nonce_offset = rp.Pop<u32>();
528 u32 nonce_size = rp.Pop<u32>();
529 size_t desc_size;
530 IPC::MappedBufferPermissions desc_permission;
531 const VAddr input = rp.PopMappedBuffer(&desc_size, &desc_permission);
532 ASSERT(desc_size == input_size && desc_permission == IPC::MappedBufferPermissions::R);
533 const VAddr output = rp.PopMappedBuffer(&desc_size, &desc_permission);
534 ASSERT(desc_size == output_size && desc_permission == IPC::MappedBufferPermissions::W);
535
536 // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't
537 // check the buffer size and writes data with potential overflow.
538 ASSERT_MSG(output_size == input_size - HW::AES::CCM_MAC_SIZE,
539 "input_size (%d) doesn't match to output_size (%d)", input_size, output_size);
540
541 LOG_DEBUG(Service_APT, "called, output_size=%u, input_size=%u, nonce_offset=%u, nonce_size=%u",
542 output_size, input_size, nonce_offset, nonce_size);
543
544 // Note: This weird nonce size modification is verified against real 3DS
545 nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE);
546
547 // Reads nonce and cipher text
548 HW::AES::CCMNonce nonce{};
549 Memory::ReadBlock(input, nonce.data(), nonce_size);
550 u32 cipher_size = input_size - nonce_size;
551 std::vector<u8> cipher(cipher_size);
552 Memory::ReadBlock(input + nonce_size, cipher.data(), cipher_size);
553
554 // Decrypts the ciphertext using AES-CCM
555 auto pdata = HW::AES::DecryptVerifyCCM(cipher, nonce, HW::AES::KeySlotID::APTWrap);
556
557 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
558 if (!pdata.empty()) {
559 // Splits the plaintext and put the nonce in between
560 Memory::WriteBlock(output, pdata.data(), nonce_offset);
561 Memory::WriteBlock(output + nonce_offset, nonce.data(), nonce_size);
562 Memory::WriteBlock(output + nonce_offset + nonce_size, pdata.data() + nonce_offset,
563 pdata.size() - nonce_offset);
564 rb.Push(RESULT_SUCCESS);
565 } else {
566 LOG_ERROR(Service_APT, "Failed to decrypt data");
567 rb.Push(ResultCode(static_cast<ErrorDescription>(1), ErrorModule::PS,
568 ErrorSummary::WrongArgument, ErrorLevel::Status));
569 }
570
571 // Unmap buffer
572 rb.PushMappedBuffer(input, input_size, IPC::MappedBufferPermissions::R);
573 rb.PushMappedBuffer(output, output_size, IPC::MappedBufferPermissions::W);
574}
575
473void CheckNew3DSApp(Service::Interface* self) { 576void CheckNew3DSApp(Service::Interface* self) {
474 u32* cmd_buff = Kernel::GetCommandBuffer(); 577 u32* cmd_buff = Kernel::GetCommandBuffer();
475 578
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 80325361f..e63b61450 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -137,6 +137,46 @@ void Initialize(Service::Interface* self);
137void GetSharedFont(Service::Interface* self); 137void GetSharedFont(Service::Interface* self);
138 138
139/** 139/**
140 * APT::Wrap service function
141 * Inputs:
142 * 1 : Output buffer size
143 * 2 : Input buffer size
144 * 3 : Nonce offset to the input buffer
145 * 4 : Nonce size
146 * 5 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xA)
147 * 6 : Input buffer address
148 * 7 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xC)
149 * 8 : Output buffer address
150 * Outputs:
151 * 1 : Result of function, 0 on success, otherwise error code
152 * 2 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xA)
153 * 3 : Input buffer address
154 * 4 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xC)
155 * 5 : Output buffer address
156 */
157void Wrap(Service::Interface* self);
158
159/**
160 * APT::Unwrap service function
161 * Inputs:
162 * 1 : Output buffer size
163 * 2 : Input buffer size
164 * 3 : Nonce offset to the output buffer
165 * 4 : Nonce size
166 * 5 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xA)
167 * 6 : Input buffer address
168 * 7 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xC)
169 * 8 : Output buffer address
170 * Outputs:
171 * 1 : Result of function, 0 on success, otherwise error code
172 * 2 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xA)
173 * 3 : Input buffer address
174 * 4 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xC)
175 * 5 : Output buffer address
176 */
177void Unwrap(Service::Interface* self);
178
179/**
140 * APT::NotifyToWait service function 180 * APT::NotifyToWait service function
141 * Inputs: 181 * Inputs:
142 * 1 : AppID 182 * 1 : AppID
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 62dc2d61d..c496cba8d 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -78,8 +78,8 @@ const Interface::FunctionInfo FunctionTable[] = {
78 {0x00430040, NotifyToWait, "NotifyToWait"}, 78 {0x00430040, NotifyToWait, "NotifyToWait"},
79 {0x00440000, GetSharedFont, "GetSharedFont"}, 79 {0x00440000, GetSharedFont, "GetSharedFont"},
80 {0x00450040, nullptr, "GetWirelessRebootInfo"}, 80 {0x00450040, nullptr, "GetWirelessRebootInfo"},
81 {0x00460104, nullptr, "Wrap"}, 81 {0x00460104, Wrap, "Wrap"},
82 {0x00470104, nullptr, "Unwrap"}, 82 {0x00470104, Unwrap, "Unwrap"},
83 {0x00480100, nullptr, "GetProgramInfo"}, 83 {0x00480100, nullptr, "GetProgramInfo"},
84 {0x00490180, nullptr, "Reboot"}, 84 {0x00490180, nullptr, "Reboot"},
85 {0x004A0040, nullptr, "GetCaptureInfo"}, 85 {0x004A0040, nullptr, "GetCaptureInfo"},
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index effd23dce..ec5668d05 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -78,8 +78,8 @@ const Interface::FunctionInfo FunctionTable[] = {
78 {0x00430040, NotifyToWait, "NotifyToWait"}, 78 {0x00430040, NotifyToWait, "NotifyToWait"},
79 {0x00440000, GetSharedFont, "GetSharedFont"}, 79 {0x00440000, GetSharedFont, "GetSharedFont"},
80 {0x00450040, nullptr, "GetWirelessRebootInfo"}, 80 {0x00450040, nullptr, "GetWirelessRebootInfo"},
81 {0x00460104, nullptr, "Wrap"}, 81 {0x00460104, Wrap, "Wrap"},
82 {0x00470104, nullptr, "Unwrap"}, 82 {0x00470104, Unwrap, "Unwrap"},
83 {0x00480100, nullptr, "GetProgramInfo"}, 83 {0x00480100, nullptr, "GetProgramInfo"},
84 {0x00490180, nullptr, "Reboot"}, 84 {0x00490180, nullptr, "Reboot"},
85 {0x004A0040, nullptr, "GetCaptureInfo"}, 85 {0x004A0040, nullptr, "GetCaptureInfo"},
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index e06084a1e..9dd002590 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -78,8 +78,8 @@ const Interface::FunctionInfo FunctionTable[] = {
78 {0x00430040, NotifyToWait, "NotifyToWait"}, 78 {0x00430040, NotifyToWait, "NotifyToWait"},
79 {0x00440000, GetSharedFont, "GetSharedFont"}, 79 {0x00440000, GetSharedFont, "GetSharedFont"},
80 {0x00450040, nullptr, "GetWirelessRebootInfo"}, 80 {0x00450040, nullptr, "GetWirelessRebootInfo"},
81 {0x00460104, nullptr, "Wrap"}, 81 {0x00460104, Wrap, "Wrap"},
82 {0x00470104, nullptr, "Unwrap"}, 82 {0x00470104, Unwrap, "Unwrap"},
83 {0x00480100, nullptr, "GetProgramInfo"}, 83 {0x00480100, nullptr, "GetProgramInfo"},
84 {0x00490180, nullptr, "Reboot"}, 84 {0x00490180, nullptr, "Reboot"},
85 {0x004A0040, nullptr, "GetCaptureInfo"}, 85 {0x004A0040, nullptr, "GetCaptureInfo"},