Exemplo n.º 1
0
	int AESContext::cryptCBC(State & state, mbedtls_aes_context * context){
		Stack * stack = state.stack;
		if (stack->is<LUA_TNUMBER>(1) && stack->is<LUA_TSTRING>(2) && stack->is<LUA_TSTRING>(3)){
			std::string ivStr = stack->toLString(2);
			std::string input = stack->toLString(3);
			size_t length = input.length();
			
			if (((length % 16) == 0) && (ivStr.length() == 16)){
				int mode = stack->to<int>(1);
				unsigned char iv[16];
				unsigned char * output = new unsigned char[length];
				memcpy(iv, ivStr.c_str(), 16);

				int result = mbedtls_aes_crypt_cbc(context, mode, length, iv, reinterpret_cast<const unsigned char *>(input.c_str()), output);
				if (result == 0){
					stack->pushLString(std::string(reinterpret_cast<char*>(iv), 16));
					stack->pushLString(std::string(reinterpret_cast<char*>(output), length));
					delete[] output;
					return 2;
				}
				else{
					stack->push<int>(result);
					delete[] output;
					return 1;
				}
			}
			else{
				stack->push<bool>(false);
				return 1;
			}

		}
		return 0;
	}
Exemplo n.º 2
0
std::vector<u8> CNANDContentLoader::AESDecode(const u8* key, u8* iv, const u8* src, u32 size)
{
	mbedtls_aes_context aes_ctx;
	std::vector<u8> buffer(size);

	mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
	mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data());

	return buffer;
}
Exemplo n.º 3
0
//AES/CBC/PKCS5Padding
//key只能是16、24、32个ASSCII字符组成的串儿
unsigned char* aes_cbc_pkcs5padding_decode(unsigned char *input, size_t inputLength, size_t *outputLength, const char *key) {
    size_t keyLength = strlen(key);
    printf("keyLength = %zu\n", keyLength);
    
    if (keyLength != 32 && keyLength != 24 && keyLength != 16) {
        perror("key必须是16、24、32个ASSCII字符组成的串\n");
        return NULL;
    }
    
    mbedtls_aes_context aes;
    
    //初始向量,一般是一个随机数组成的,长度必须是块大小,一个块是16字节,也就是16个ASCII字符
    unsigned char iv[16];
    memcpy(iv, key, keyLength);
    
    //解密后的数据长度
    unsigned char *output = (unsigned char *)calloc(inputLength, sizeof(unsigned char));
    
    //设置加密的key,并初始化
    mbedtls_aes_setkey_dec(&aes, (unsigned char*)key, keyLength * 8);
    
    //加密数据
    mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, inputLength, iv, input, output);
    
    int outputLastIndex = inputLength - 1;

    //取出output最后一个字节,转成数字
    unsigned int lastValue = output[outputLastIndex];
    printf("lastValue = %d\n", lastValue);
    if (lastValue > 0 && lastValue <= 16) {
        int j = outputLastIndex;
        while(output[j] == lastValue) {
            j--;
        }
        printf("j = %d\n", j);
        *outputLength = j + 1;
        outputLastIndex = j;
    }

    size_t inputHexLength = 2 * inputLength + 1;
    char inputHex[inputHexLength];
    memset(inputHex, 0, inputHexLength);
    bytes2HexStr(inputHex, input, inputLength);
    
    size_t outputHexLength = 2 * inputLength + 1;
    char outputHex[outputHexLength];
    memset(outputHex, 0, outputHexLength);
    bytes2HexStr(outputHex, output, inputLength);

    printf("aesDecode(%s, %s)=%s\n", inputHex, key, outputHex);
    
    return output;
}
Exemplo n.º 4
0
bool CVolumeWiiCrypted::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, bool decrypt) const
{
  if (m_pReader == nullptr)
    return false;

  if (!decrypt)
    return m_pReader->Read(_ReadOffset, _Length, _pBuffer);

  FileMon::FindFilename(_ReadOffset);

  std::vector<u8> read_buffer(s_block_total_size);
  while (_Length > 0)
  {
    // Calculate block offset
    u64 Block = _ReadOffset / s_block_data_size;
    u64 Offset = _ReadOffset % s_block_data_size;

    if (m_LastDecryptedBlockOffset != Block)
    {
      // Read the current block
      if (!m_pReader->Read(m_VolumeOffset + m_dataOffset + Block * s_block_total_size,
                           s_block_total_size, read_buffer.data()))
        return false;

      // Decrypt the block's data.
      // 0x3D0 - 0x3DF in m_pBuffer will be overwritten,
      // but that won't affect anything, because we won't
      // use the content of m_pBuffer anymore after this
      mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, s_block_data_size,
                            &read_buffer[0x3D0], &read_buffer[s_block_header_size],
                            m_LastDecryptedBlock);
      m_LastDecryptedBlockOffset = Block;

      // The only thing we currently use from the 0x000 - 0x3FF part
      // of the block is the IV (at 0x3D0), but it also contains SHA-1
      // hashes that IOS uses to check that discs aren't tampered with.
      // http://wiibrew.org/wiki/Wii_Disc#Encrypted
    }

    // Copy the decrypted data
    u64 MaxSizeToCopy = s_block_data_size - Offset;
    u64 CopySize = (_Length > MaxSizeToCopy) ? MaxSizeToCopy : _Length;
    memcpy(_pBuffer, &m_LastDecryptedBlock[Offset], (size_t)CopySize);

    // Update offsets
    _Length -= CopySize;
    _pBuffer += CopySize;
    _ReadOffset += CopySize;
  }

  return true;
}
Exemplo n.º 5
0
int compute_cmac_( mbedtls_aes_context *ctx,
		          const unsigned char *input,
		          size_t length,
		          unsigned char param,
		          unsigned char mac[16] )
{
	unsigned char buf[16], iv[16];
	memset(buf, 0, sizeof(buf));
	buf[15] = param;
	memset(iv, 0, sizeof(iv));
	length += 16;

	unsigned char pad[16];
	memset(pad, 0, sizeof(pad));
	mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, pad, pad);
	gf128_double_(pad);
	if (length & 15) {
		gf128_double_(pad);
		pad[length & 15] ^= 0x80;
	}

	const unsigned char *tmp_input = buf;
	while (length > 16) {
		mbedtls_aes_crypt_cbc(ctx, MBEDTLS_AES_ENCRYPT, 16, iv, tmp_input, buf);
		if (tmp_input == buf) {
			tmp_input = input;
		} else {
			tmp_input += 16;
		}
		length -= 16;
	}

	size_t i;
	for (i = 0; i < length; i++)
		pad[i] ^= tmp_input[i];

	mbedtls_aes_crypt_cbc(ctx, MBEDTLS_AES_ENCRYPT, 16, iv, pad, mac);
	return 0;
}
Exemplo n.º 6
0
bool mgos_vfs_fs_spiffs_decrypt_block(spiffs_obj_id obj_id, uint32_t offset,
                                      void *data, uint32_t len) {
  if (len % 16 != 0) return false;
  uint8_t *p = (uint8_t *) data;
  while (len > 0) {
    uint32_t iv[4] = {0xdeadbeef, obj_id, 0x900df00d, offset};
    if (mbedtls_aes_crypt_cbc(&s_aes_ctx_dec, MBEDTLS_AES_DECRYPT, 16,
                              (uint8_t *) iv, p, p) != 0) {
      return false;
    }
    p += 16;
    len -= 16;
    offset += 16;
  }
  return true;
}
Exemplo n.º 7
0
void VolumeKeyForPartition(IBlobReader& _rReader, u64 offset, u8* VolumeKey)
{
	CBlobBigEndianReader Reader(_rReader);

	u8 SubKey[16];
	_rReader.Read(offset + 0x1bf, 16, SubKey);

	u8 IV[16];
	memset(IV, 0, 16);
	_rReader.Read(offset + 0x44c, 8, IV);

	bool usingKoreanKey = false;
	// Issue: 6813
	// Magic value is at partition's offset + 0x1f1 (1byte)
	// If encrypted with the Korean key, the magic value would be 1
	// Otherwise it is zero
	if (Reader.Read8(0x3) == 'K' && Reader.Read8(offset + 0x1f1) == 1)
		usingKoreanKey = true;

	mbedtls_aes_context AES_ctx;
	mbedtls_aes_setkey_dec(&AES_ctx, (usingKoreanKey ? s_master_key_korean : s_master_key), 128);

	mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, 16, IV, SubKey, VolumeKey);
}
Exemplo n.º 8
0
IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
{
  s32 return_error_code = IPC_SUCCESS;

  switch (request.request)
  {
  case IOCTL_WFSI_IMPORT_TITLE_INIT:
  {
    u32 tmd_addr = Memory::Read_U32(request.buffer_in);
    u32 tmd_size = Memory::Read_U32(request.buffer_in + 4);

    m_patch_type = static_cast<PatchType>(Memory::Read_U32(request.buffer_in + 32));
    m_continue_install = Memory::Read_U32(request.buffer_in + 36);

    INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: patch type %d, continue install: %s",
             m_patch_type, m_continue_install ? "true" : "false");

    if (m_patch_type == PatchType::PATCH_TYPE_2)
    {
      const std::string content_dir =
          StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(),
                           m_current_group_id_str.c_str(), m_current_title_id_str.c_str());

      File::Rename(WFS::NativePath(content_dir + "/default.dol"),
                   WFS::NativePath(content_dir + "/_default.dol"));
    }

    if (!IOS::ES::IsValidTMDSize(tmd_size))
    {
      ERROR_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: TMD size too large (%d)", tmd_size);
      return_error_code = IPC_EINVAL;
      break;
    }
    std::vector<u8> tmd_bytes;
    tmd_bytes.resize(tmd_size);
    Memory::CopyFromEmu(tmd_bytes.data(), tmd_addr, tmd_size);
    m_tmd.SetBytes(std::move(tmd_bytes));

    IOS::ES::TicketReader ticket = m_ios.GetES()->FindSignedTicket(m_tmd.GetTitleId());
    if (!ticket.IsValid())
    {
      return_error_code = -11028;
      break;
    }

    memcpy(m_aes_key, ticket.GetTitleKey(m_ios.GetIOSC()).data(), sizeof(m_aes_key));
    mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128);

    SetImportTitleIdAndGroupId(m_tmd.GetTitleId(), m_tmd.GetGroupId());

    if (m_patch_type == PatchType::PATCH_TYPE_1)
      CancelPatchImport(m_continue_install);
    else if (m_patch_type == PatchType::NOT_A_PATCH)
      CancelTitleImport(m_continue_install);

    break;
  }

  case IOCTL_WFSI_PREPARE_PROFILE:
    m_base_extract_path = StringFromFormat("/vol/%s/tmp/", m_device_name.c_str());
    // Fall through intended.

  case IOCTL_WFSI_PREPARE_CONTENT:
  {
    const char* ioctl_name = request.request == IOCTL_WFSI_PREPARE_PROFILE ?
                                 "IOCTL_WFSI_PREPARE_PROFILE" :
                                 "IOCTL_WFSI_PREPARE_CONTENT";

    // Initializes the IV from the index of the content in the TMD contents.
    u32 content_id = Memory::Read_U32(request.buffer_in + 8);
    IOS::ES::Content content_info;
    if (!m_tmd.FindContentById(content_id, &content_info))
    {
      WARN_LOG(IOS_WFS, "%s: Content id %08x not found", ioctl_name, content_id);
      return_error_code = -10003;
      break;
    }

    memset(m_aes_iv, 0, sizeof(m_aes_iv));
    m_aes_iv[0] = content_info.index >> 8;
    m_aes_iv[1] = content_info.index & 0xFF;
    INFO_LOG(IOS_WFS, "%s: Content id %08x found at index %d", ioctl_name, content_id,
             content_info.index);

    m_arc_unpacker.Reset();
    break;
  }

  case IOCTL_WFSI_IMPORT_PROFILE:
  case IOCTL_WFSI_IMPORT_CONTENT:
  {
    const char* ioctl_name = request.request == IOCTL_WFSI_IMPORT_PROFILE ?
                                 "IOCTL_WFSI_IMPORT_PROFILE" :
                                 "IOCTL_WFSI_IMPORT_CONTENT";

    u32 content_id = Memory::Read_U32(request.buffer_in + 0xC);
    u32 input_ptr = Memory::Read_U32(request.buffer_in + 0x10);
    u32 input_size = Memory::Read_U32(request.buffer_in + 0x14);
    INFO_LOG(IOS_WFS, "%s: %08x bytes of data at %08x from content id %d", ioctl_name, input_size,
             input_ptr, content_id);

    std::vector<u8> decrypted(input_size);
    mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, input_size, m_aes_iv,
                          Memory::GetPointer(input_ptr), decrypted.data());

    m_arc_unpacker.AddBytes(decrypted);
    break;
  }

  case IOCTL_WFSI_IMPORT_CONTENT_END:
  case IOCTL_WFSI_IMPORT_PROFILE_END:
  {
    const char* ioctl_name = request.request == IOCTL_WFSI_IMPORT_PROFILE_END ?
                                 "IOCTL_WFSI_IMPORT_PROFILE_END" :
                                 "IOCTL_WFSI_IMPORT_CONTENT_END";
    INFO_LOG(IOS_WFS, "%s", ioctl_name);

    auto callback = [this](const std::string& filename, const std::vector<u8>& bytes) {
      INFO_LOG(IOS_WFS, "Extract: %s (%zd bytes)", filename.c_str(), bytes.size());

      std::string path = WFS::NativePath(m_base_extract_path + "/" + filename);
      File::CreateFullPath(path);
      File::IOFile f(path, "wb");
      if (!f)
      {
        ERROR_LOG(IOS_WFS, "Could not extract %s to %s", filename.c_str(), path.c_str());
        return;
      }
      f.WriteBytes(bytes.data(), bytes.size());
    };
    m_arc_unpacker.Extract(callback);

    // Technically not needed, but let's not keep large buffers in RAM for no
    // reason if we can avoid it.
    m_arc_unpacker.Reset();
    break;
  }

  case IOCTL_WFSI_FINALIZE_TITLE_INSTALL:
  {
    std::string tmd_path;
    if (m_patch_type == NOT_A_PATCH)
    {
      std::string title_install_dir = StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(),
                                                       m_import_title_id_str.c_str());
      std::string title_final_dir =
          StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(),
                           m_import_group_id_str.c_str(), m_import_title_id_str.c_str());
      File::Rename(WFS::NativePath(title_install_dir), WFS::NativePath(title_final_dir));

      tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd",
                                  m_device_name.c_str(), m_import_group_id_str.c_str(),
                                  m_import_title_id_str.c_str(), m_import_title_id);
    }
    else
    {
      std::string patch_dir =
          StringFromFormat("/vol/%s/title/%s/%s/_patch", m_device_name.c_str(),
                           m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
      File::DeleteDirRecursively(WFS::NativePath(patch_dir));

      tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd",
                                  m_device_name.c_str(), m_current_group_id_str.c_str(),
                                  m_current_title_id_str.c_str(), m_import_title_id);
    }

    File::IOFile tmd_file(WFS::NativePath(tmd_path), "wb");
    tmd_file.WriteBytes(m_tmd.GetBytes().data(), m_tmd.GetBytes().size());
    break;
  }

  case IOCTL_WFSI_FINALIZE_PATCH_INSTALL:
  {
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_FINALIZE_PATCH_INSTALL");
    if (m_patch_type != NOT_A_PATCH)
    {
      std::string current_title_dir =
          StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(),
                           m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
      std::string patch_dir = current_title_dir + "/_patch";
      File::CopyDir(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir), true);
    }
    break;
  }

  case IOCTL_WFSI_DELETE_TITLE:
    // Bytes 0-4: ??
    // Bytes 4-8: game id
    // Bytes 1c-1e: title id?
    WARN_LOG(IOS_WFS, "IOCTL_WFSI_DELETE_TITLE: unimplemented");
    break;

  case IOCTL_WFSI_GET_VERSION:
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_VERSION");
    Memory::Write_U32(0x20, request.buffer_out);
    break;

  case IOCTL_WFSI_IMPORT_TITLE_CANCEL:
  {
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_CANCEL");

    bool continue_install = Memory::Read_U32(request.buffer_in) != 0;
    if (m_patch_type == PatchType::NOT_A_PATCH)
      return_error_code = CancelTitleImport(continue_install);
    else if (m_patch_type == PatchType::PATCH_TYPE_1 || m_patch_type == PatchType::PATCH_TYPE_2)
      return_error_code = CancelPatchImport(continue_install);
    else
      return_error_code = WFS_EINVAL;

    m_tmd = {};
    break;
  }

  case IOCTL_WFSI_INIT:
  {
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_INIT");
    u64 tid;
    if (GetIOS()->GetES()->GetTitleId(&tid) < 0)
    {
      ERROR_LOG(IOS_WFS, "IOCTL_WFSI_INIT: Could not get title id.");
      return_error_code = IPC_EINVAL;
      break;
    }

    IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(tid);
    SetCurrentTitleIdAndGroupId(tmd.GetTitleId(), tmd.GetGroupId());
    break;
  }

  case IOCTL_WFSI_SET_DEVICE_NAME:
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_SET_DEVICE_NAME");
    m_device_name = Memory::GetString(request.buffer_in);
    break;

  case IOCTL_WFSI_APPLY_TITLE_PROFILE:
  {
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_APPLY_TITLE_PROFILE");

    if (m_patch_type == NOT_A_PATCH)
    {
      std::string install_directory = StringFromFormat("/vol/%s/_install", m_device_name.c_str());
      if (!m_continue_install && File::IsDirectory(WFS::NativePath(install_directory)))
      {
        File::DeleteDirRecursively(WFS::NativePath(install_directory));
      }

      m_base_extract_path = StringFromFormat("%s/%s/content", install_directory.c_str(),
                                             m_import_title_id_str.c_str());
      File::CreateFullPath(WFS::NativePath(m_base_extract_path));
      File::CreateDir(WFS::NativePath(m_base_extract_path));

      for (auto dir : {"work", "meta", "save"})
      {
        std::string path = StringFromFormat("%s/%s/%s", install_directory.c_str(),
                                            m_import_title_id_str.c_str(), dir);
        File::CreateDir(WFS::NativePath(path));
      }

      std::string group_path = StringFromFormat("/vol/%s/title/%s", m_device_name.c_str(),
                                                m_import_group_id_str.c_str());
      File::CreateFullPath(WFS::NativePath(group_path));
      File::CreateDir(WFS::NativePath(group_path));
    }
    else
    {
      m_base_extract_path =
          StringFromFormat("/vol/%s/title/%s/%s/_patch/content", m_device_name.c_str(),
                           m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
      File::CreateFullPath(WFS::NativePath(m_base_extract_path));
      File::CreateDir(WFS::NativePath(m_base_extract_path));
    }

    break;
  }

  case IOCTL_WFSI_GET_TMD:
  {
    u64 subtitle_id = Memory::Read_U64(request.buffer_in);
    u32 address = Memory::Read_U32(request.buffer_in + 24);
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD: subtitle ID %016" PRIx64, subtitle_id);

    u32 tmd_size;
    return_error_code =
        GetTmd(m_current_group_id, m_current_title_id, subtitle_id, address, &tmd_size);
    Memory::Write_U32(tmd_size, request.buffer_out);
    break;
  }

  case IOCTL_WFSI_GET_TMD_ABSOLUTE:
  {
    u64 subtitle_id = Memory::Read_U64(request.buffer_in);
    u32 address = Memory::Read_U32(request.buffer_in + 24);
    u16 group_id = Memory::Read_U16(request.buffer_in + 36);
    u32 title_id = Memory::Read_U32(request.buffer_in + 32);
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD_ABSOLUTE: tid %08x, gid %04x, subtitle ID %016" PRIx64,
             title_id, group_id, subtitle_id);

    u32 tmd_size;
    return_error_code = GetTmd(group_id, title_id, subtitle_id, address, &tmd_size);
    Memory::Write_U32(tmd_size, request.buffer_out);
    break;
  }

  case IOCTL_WFSI_SET_FST_BUFFER:
  {
    INFO_LOG(IOS_WFS, "IOCTL_WFSI_SET_FST_BUFFER: address %08x, size %08x", request.buffer_in,
             request.buffer_in_size);
    break;
  }

  case IOCTL_WFSI_NOOP:
    break;

  case IOCTL_WFSI_LOAD_DOL:
  {
    std::string path =
        StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(),
                         m_current_group_id_str.c_str(), m_current_title_id_str.c_str());

    u32 dol_addr = Memory::Read_U32(request.buffer_in + 0x18);
    u32 max_dol_size = Memory::Read_U32(request.buffer_in + 0x14);
    u16 dol_extension_id = Memory::Read_U16(request.buffer_in + 0x1e);

    if (dol_extension_id == 0)
    {
      path += "/default.dol";
    }
    else
    {
      path += StringFromFormat("/extension%d.dol", dol_extension_id);
    }

    INFO_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: loading %s at address %08x (size %d)", path.c_str(),
             dol_addr, max_dol_size);

    File::IOFile fp(WFS::NativePath(path), "rb");
    if (!fp)
    {
      WARN_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str());
      return_error_code = WFS_ENOENT;
      break;
    }

    u32 real_dol_size = fp.GetSize();
    if (dol_addr == 0)
    {
      // Write the expected size to the size parameter, in the input.
      Memory::Write_U32(real_dol_size, request.buffer_in + 0x14);
    }
    else
    {
      fp.ReadBytes(Memory::GetPointer(dol_addr), max_dol_size);
    }
    Memory::Write_U32(real_dol_size, request.buffer_out);
    break;
  }

  case IOCTL_WFSI_CHECK_HAS_SPACE:
    WARN_LOG(IOS_WFS, "IOCTL_WFSI_CHECK_HAS_SPACE: returning true");

    // TODO(wfs): implement this properly.
    //       1 is returned if there is free space, 0 otherwise.
    //
    // WFSI builds a path depending on the import state
    //   /vol/VOLUME_ID/title/GROUP_ID/GAME_ID
    //   /vol/VOLUME_ID/_install/GAME_ID
    // then removes everything after the last path separator ('/')
    // it then calls WFSISrvGetFreeBlkNum (ioctl 0x5a, aliased to 0x5b) with that path.
    // If the ioctl fails, WFSI returns 0.
    // If the ioctl succeeds, WFSI returns 0 or 1 depending on the three u32s in the input buffer
    // and the three u32s returned by WFSSRV (TODO: figure out what it does)
    return_error_code = 1;
    break;

  default:
    // TODO(wfs): Should be returning an error. However until we have
    // everything properly stubbed it's easier to simulate the methods
    // succeeding.
    request.DumpUnknown(GetDeviceName(), LogTypes::IOS, LogTypes::LWARNING);
    Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
    break;
  }

  return GetDefaultReply(return_error_code);
}
Exemplo n.º 9
0
int main( int argc, char *argv[] )
{
    int i;
    unsigned char tmp[200];
    char title[TITLE_LEN];
    todo_list todo;
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
    unsigned char alloc_buf[HEAP_SIZE] = { 0 };
#endif

    if( argc <= 1 )
    {
        memset( &todo, 1, sizeof( todo ) );
    }
    else
    {
        memset( &todo, 0, sizeof( todo ) );

        for( i = 1; i < argc; i++ )
        {
            if( strcmp( argv[i], "md4" ) == 0 )
                todo.md4 = 1;
            else if( strcmp( argv[i], "md5" ) == 0 )
                todo.md5 = 1;
            else if( strcmp( argv[i], "ripemd160" ) == 0 )
                todo.ripemd160 = 1;
            else if( strcmp( argv[i], "sha1" ) == 0 )
                todo.sha1 = 1;
            else if( strcmp( argv[i], "sha256" ) == 0 )
                todo.sha256 = 1;
            else if( strcmp( argv[i], "sha512" ) == 0 )
                todo.sha512 = 1;
            else if( strcmp( argv[i], "arc4" ) == 0 )
                todo.arc4 = 1;
            else if( strcmp( argv[i], "des3" ) == 0 )
                todo.des3 = 1;
            else if( strcmp( argv[i], "des" ) == 0 )
                todo.des = 1;
            else if( strcmp( argv[i], "aes_cbc" ) == 0 )
                todo.aes_cbc = 1;
            else if( strcmp( argv[i], "aes_gcm" ) == 0 )
                todo.aes_gcm = 1;
            else if( strcmp( argv[i], "aes_ccm" ) == 0 )
                todo.aes_ccm = 1;
            else if( strcmp( argv[i], "aes_cmac" ) == 0 )
                todo.aes_cmac = 1;
            else if( strcmp( argv[i], "des3_cmac" ) == 0 )
                todo.des3_cmac = 1;
            else if( strcmp( argv[i], "camellia" ) == 0 )
                todo.camellia = 1;
            else if( strcmp( argv[i], "blowfish" ) == 0 )
                todo.blowfish = 1;
            else if( strcmp( argv[i], "havege" ) == 0 )
                todo.havege = 1;
            else if( strcmp( argv[i], "ctr_drbg" ) == 0 )
                todo.ctr_drbg = 1;
            else if( strcmp( argv[i], "hmac_drbg" ) == 0 )
                todo.hmac_drbg = 1;
            else if( strcmp( argv[i], "rsa" ) == 0 )
                todo.rsa = 1;
            else if( strcmp( argv[i], "dhm" ) == 0 )
                todo.dhm = 1;
            else if( strcmp( argv[i], "ecdsa" ) == 0 )
                todo.ecdsa = 1;
            else if( strcmp( argv[i], "ecdh" ) == 0 )
                todo.ecdh = 1;
            else
            {
                mbedtls_printf( "Unrecognized option: %s\n", argv[i] );
                mbedtls_printf( "Available options: " OPTIONS );
            }
        }
    }

    mbedtls_printf( "\n" );

#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
    mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof( alloc_buf ) );
#endif
    memset( buf, 0xAA, sizeof( buf ) );
    memset( tmp, 0xBB, sizeof( tmp ) );

#if defined(MBEDTLS_MD4_C)
    if( todo.md4 )
        TIME_AND_TSC( "MD4", mbedtls_md4_ret( buf, BUFSIZE, tmp ) );
#endif

#if defined(MBEDTLS_MD5_C)
    if( todo.md5 )
        TIME_AND_TSC( "MD5", mbedtls_md5_ret( buf, BUFSIZE, tmp ) );
#endif

#if defined(MBEDTLS_RIPEMD160_C)
    if( todo.ripemd160 )
        TIME_AND_TSC( "RIPEMD160", mbedtls_ripemd160_ret( buf, BUFSIZE, tmp ) );
#endif

#if defined(MBEDTLS_SHA1_C)
    if( todo.sha1 )
        TIME_AND_TSC( "SHA-1", mbedtls_sha1_ret( buf, BUFSIZE, tmp ) );
#endif

#if defined(MBEDTLS_SHA256_C)
    if( todo.sha256 )
        TIME_AND_TSC( "SHA-256", mbedtls_sha256_ret( buf, BUFSIZE, tmp, 0 ) );
#endif

#if defined(MBEDTLS_SHA512_C)
    if( todo.sha512 )
        TIME_AND_TSC( "SHA-512", mbedtls_sha512_ret( buf, BUFSIZE, tmp, 0 ) );
#endif

#if defined(MBEDTLS_ARC4_C)
    if( todo.arc4 )
    {
        mbedtls_arc4_context arc4;
        mbedtls_arc4_init( &arc4 );
        mbedtls_arc4_setup( &arc4, tmp, 32 );
        TIME_AND_TSC( "ARC4", mbedtls_arc4_crypt( &arc4, BUFSIZE, buf, buf ) );
        mbedtls_arc4_free( &arc4 );
    }
#endif

#if defined(MBEDTLS_DES_C)
#if defined(MBEDTLS_CIPHER_MODE_CBC)
    if( todo.des3 )
    {
        mbedtls_des3_context des3;
        mbedtls_des3_init( &des3 );
        mbedtls_des3_set3key_enc( &des3, tmp );
        TIME_AND_TSC( "3DES",
                mbedtls_des3_crypt_cbc( &des3, MBEDTLS_DES_ENCRYPT, BUFSIZE, tmp, buf, buf ) );
        mbedtls_des3_free( &des3 );
    }

    if( todo.des )
    {
        mbedtls_des_context des;
        mbedtls_des_init( &des );
        mbedtls_des_setkey_enc( &des, tmp );
        TIME_AND_TSC( "DES",
                mbedtls_des_crypt_cbc( &des, MBEDTLS_DES_ENCRYPT, BUFSIZE, tmp, buf, buf ) );
        mbedtls_des_free( &des );
    }

#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CMAC_C)
    if( todo.des3_cmac )
    {
        unsigned char output[8];
        const mbedtls_cipher_info_t *cipher_info;

        memset( buf, 0, sizeof( buf ) );
        memset( tmp, 0, sizeof( tmp ) );

        cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_DES_EDE3_ECB );

        TIME_AND_TSC( "3DES-CMAC",
                      mbedtls_cipher_cmac( cipher_info, tmp, 192, buf,
                      BUFSIZE, output ) );
    }
#endif /* MBEDTLS_CMAC_C */
#endif /* MBEDTLS_DES_C */

#if defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_CIPHER_MODE_CBC)
    if( todo.aes_cbc )
    {
        int keysize;
        mbedtls_aes_context aes;
        mbedtls_aes_init( &aes );
        for( keysize = 128; keysize <= 256; keysize += 64 )
        {
            mbedtls_snprintf( title, sizeof( title ), "AES-CBC-%d", keysize );

            memset( buf, 0, sizeof( buf ) );
            memset( tmp, 0, sizeof( tmp ) );
            mbedtls_aes_setkey_enc( &aes, tmp, keysize );

            TIME_AND_TSC( title,
                mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_ENCRYPT, BUFSIZE, tmp, buf, buf ) );
        }
        mbedtls_aes_free( &aes );
    }
#endif
#if defined(MBEDTLS_GCM_C)
    if( todo.aes_gcm )
    {
        int keysize;
        mbedtls_gcm_context gcm;

        mbedtls_gcm_init( &gcm );
        for( keysize = 128; keysize <= 256; keysize += 64 )
        {
            mbedtls_snprintf( title, sizeof( title ), "AES-GCM-%d", keysize );

            memset( buf, 0, sizeof( buf ) );
            memset( tmp, 0, sizeof( tmp ) );
            mbedtls_gcm_setkey( &gcm, MBEDTLS_CIPHER_ID_AES, tmp, keysize );

            TIME_AND_TSC( title,
                    mbedtls_gcm_crypt_and_tag( &gcm, MBEDTLS_GCM_ENCRYPT, BUFSIZE, tmp,
                        12, NULL, 0, buf, buf, 16, tmp ) );

            mbedtls_gcm_free( &gcm );
        }
    }
#endif
#if defined(MBEDTLS_CCM_C)
    if( todo.aes_ccm )
    {
        int keysize;
        mbedtls_ccm_context ccm;

        mbedtls_ccm_init( &ccm );
        for( keysize = 128; keysize <= 256; keysize += 64 )
        {
            mbedtls_snprintf( title, sizeof( title ), "AES-CCM-%d", keysize );

            memset( buf, 0, sizeof( buf ) );
            memset( tmp, 0, sizeof( tmp ) );
            mbedtls_ccm_setkey( &ccm, MBEDTLS_CIPHER_ID_AES, tmp, keysize );

            TIME_AND_TSC( title,
                    mbedtls_ccm_encrypt_and_tag( &ccm, BUFSIZE, tmp,
                        12, NULL, 0, buf, buf, tmp, 16 ) );

            mbedtls_ccm_free( &ccm );
        }
    }
#endif
#if defined(MBEDTLS_CMAC_C)
    if( todo.aes_cmac )
    {
        unsigned char output[16];
        const mbedtls_cipher_info_t *cipher_info;
        mbedtls_cipher_type_t cipher_type;
        int keysize;

        for( keysize = 128, cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
             keysize <= 256;
             keysize += 64, cipher_type++ )
        {
            mbedtls_snprintf( title, sizeof( title ), "AES-CMAC-%d", keysize );

            memset( buf, 0, sizeof( buf ) );
            memset( tmp, 0, sizeof( tmp ) );

            cipher_info = mbedtls_cipher_info_from_type( cipher_type );

            TIME_AND_TSC( title,
                          mbedtls_cipher_cmac( cipher_info, tmp, keysize,
                                               buf, BUFSIZE, output ) );
        }

        memset( buf, 0, sizeof( buf ) );
        memset( tmp, 0, sizeof( tmp ) );
        TIME_AND_TSC( "AES-CMAC-PRF-128",
                      mbedtls_aes_cmac_prf_128( tmp, 16, buf, BUFSIZE,
                                                output ) );
    }
#endif /* MBEDTLS_CMAC_C */
#endif /* MBEDTLS_AES_C */

#if defined(MBEDTLS_CAMELLIA_C) && defined(MBEDTLS_CIPHER_MODE_CBC)
    if( todo.camellia )
    {
        int keysize;
        mbedtls_camellia_context camellia;
        mbedtls_camellia_init( &camellia );
        for( keysize = 128; keysize <= 256; keysize += 64 )
        {
            mbedtls_snprintf( title, sizeof( title ), "CAMELLIA-CBC-%d", keysize );

            memset( buf, 0, sizeof( buf ) );
            memset( tmp, 0, sizeof( tmp ) );
            mbedtls_camellia_setkey_enc( &camellia, tmp, keysize );

            TIME_AND_TSC( title,
                    mbedtls_camellia_crypt_cbc( &camellia, MBEDTLS_CAMELLIA_ENCRYPT,
                        BUFSIZE, tmp, buf, buf ) );
        }
        mbedtls_camellia_free( &camellia );
    }
#endif

#if defined(MBEDTLS_BLOWFISH_C) && defined(MBEDTLS_CIPHER_MODE_CBC)
    if( todo.blowfish )
    {
        int keysize;
        mbedtls_blowfish_context blowfish;
        mbedtls_blowfish_init( &blowfish );

        for( keysize = 128; keysize <= 256; keysize += 64 )
        {
            mbedtls_snprintf( title, sizeof( title ), "BLOWFISH-CBC-%d", keysize );

            memset( buf, 0, sizeof( buf ) );
            memset( tmp, 0, sizeof( tmp ) );
            mbedtls_blowfish_setkey( &blowfish, tmp, keysize );

            TIME_AND_TSC( title,
                    mbedtls_blowfish_crypt_cbc( &blowfish, MBEDTLS_BLOWFISH_ENCRYPT, BUFSIZE,
                        tmp, buf, buf ) );
        }

        mbedtls_blowfish_free( &blowfish );
    }
#endif

#if defined(MBEDTLS_HAVEGE_C)
    if( todo.havege )
    {
        mbedtls_havege_state hs;
        mbedtls_havege_init( &hs );
        TIME_AND_TSC( "HAVEGE", mbedtls_havege_random( &hs, buf, BUFSIZE ) );
        mbedtls_havege_free( &hs );
    }
#endif

#if defined(MBEDTLS_CTR_DRBG_C)
    if( todo.ctr_drbg )
    {
        mbedtls_ctr_drbg_context ctr_drbg;

        mbedtls_ctr_drbg_init( &ctr_drbg );

        if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 )
            mbedtls_exit(1);
        TIME_AND_TSC( "CTR_DRBG (NOPR)",
                if( mbedtls_ctr_drbg_random( &ctr_drbg, buf, BUFSIZE ) != 0 )
                mbedtls_exit(1) );

        if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 )
            mbedtls_exit(1);
        mbedtls_ctr_drbg_set_prediction_resistance( &ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON );
        TIME_AND_TSC( "CTR_DRBG (PR)",
                if( mbedtls_ctr_drbg_random( &ctr_drbg, buf, BUFSIZE ) != 0 )
                mbedtls_exit(1) );
        mbedtls_ctr_drbg_free( &ctr_drbg );
    }
Exemplo n.º 10
0
static NO_INLINE JsVar *jswrap_crypto_AEScrypt(JsVar *message, JsVar *key, JsVar *options, bool encrypt) {
  int err;

  unsigned char iv[16]; // initialisation vector
  memset(iv, 0, 16);

  CryptoMode mode = CM_CBC;

  if (jsvIsObject(options)) {
    JsVar *ivVar = jsvObjectGetChild(options, "iv", 0);
    if (ivVar) {
      jsvIterateCallbackToBytes(ivVar, iv, sizeof(iv));
      jsvUnLock(ivVar);
    }
    JsVar *modeVar = jsvObjectGetChild(options, "mode", 0);
    if (!jsvIsUndefined(modeVar))
      mode = jswrap_crypto_getMode(modeVar);
    jsvUnLock(modeVar);
    if (mode == CM_NONE) return 0;
  } else if (!jsvIsUndefined(options)) {
    jsError("'options' must be undefined, or an Object");
    return 0;
  }



  mbedtls_aes_context aes;
  mbedtls_aes_init( &aes );

  JSV_GET_AS_CHAR_ARRAY(messagePtr, messageLen, message);
  if (!messagePtr) return 0;

  JSV_GET_AS_CHAR_ARRAY(keyPtr, keyLen, key);
  if (!keyPtr) return 0;

  if (encrypt)
    err = mbedtls_aes_setkey_enc( &aes, (unsigned char*)keyPtr, (unsigned int)keyLen*8 );
  else
    err = mbedtls_aes_setkey_dec( &aes, (unsigned char*)keyPtr, (unsigned int)keyLen*8 );
  if (err) {
    jswrap_crypto_error(err);
    return 0;
  }

  char *outPtr = 0;
  JsVar *outVar = jsvNewArrayBufferWithPtr((unsigned int)messageLen, &outPtr);
  if (!outPtr) {
    jsError("Not enough memory for result");
    return 0;
  }



  switch (mode) {
  case CM_CBC:
    err = mbedtls_aes_crypt_cbc( &aes,
                     encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT,
                     messageLen,
                     iv,
                     (unsigned char*)messagePtr,
                     (unsigned char*)outPtr );
    break;
  case CM_CFB:
    err = mbedtls_aes_crypt_cfb8( &aes,
                     encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT,
                     messageLen,
                     iv,
                     (unsigned char*)messagePtr,
                     (unsigned char*)outPtr );
    break;
  case CM_CTR: {
    size_t nc_off = 0;
    unsigned char nonce_counter[16];
    unsigned char stream_block[16];
    memset(nonce_counter, 0, sizeof(nonce_counter));
    memset(stream_block, 0, sizeof(stream_block));
    err = mbedtls_aes_crypt_ctr( &aes,
                     messageLen,
                     &nc_off,
                     nonce_counter,
                     stream_block,
                     (unsigned char*)messagePtr,
                     (unsigned char*)outPtr );
    break;
  }
  case CM_ECB: {
    size_t i = 0;
    while (!err && i+15 < messageLen) {
      err = mbedtls_aes_crypt_ecb( &aes,
                       encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT,
                       (unsigned char*)&messagePtr[i],
                       (unsigned char*)&outPtr[i] );
      i += 16;
    }
    break;
  }
  default:
    err = MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
    break;
  }

  mbedtls_aes_free( &aes );
  if (!err) {
    return outVar;
  } else {
    jswrap_crypto_error(err);
    jsvUnLock(outVar);
    return 0;
  }
}
Exemplo n.º 11
0
//AES/CBC/PKCS5Padding
//input可以是任意长度
//key只能是16、24、32个ASSCII字符组成的串儿
unsigned char* aes_cbc_pkcs5padding_encode(const char *input, const char *key, size_t *outputLength) {
    size_t keyLength = strlen(key);
    printf("keyLength = %zu\n", keyLength);

    if (keyLength != 32 && keyLength != 24 && keyLength != 16) {
        perror("key必须是16、24、32个ASSCII字符组成的串\n");
        return NULL;
    }
        
    mbedtls_aes_context aes;

    //获取到输入的要加密的内容的长度
    size_t inputLength = strlen(input);
    printf("input = %s, inputLength = %zu\n", input, inputLength);

    //看看需要分成多少个块,即使输入的数据是16的整数倍,也要补充16个字节的整数16
    size_t n = inputLength / 16 + 1;

    //https://tools.ietf.org/html/rfc8018#appendix-B.2.5
    int padding = 16 - inputLength % 8;

    //用于加密的的数据长度:字节数,此字节数正好等于输出的字节数
    int needInputLength = 16 * n;
    *outputLength = needInputLength;

    //初始向量,一般是一个随机数组成的,长度必须是块大小,一个块是16字节,也就是16个ASCII字符
    unsigned char iv[16];
    memcpy(iv, key, keyLength);

    unsigned char *toBeEncryptBytes = (unsigned char *)calloc(needInputLength + 1, sizeof(unsigned char));
    memcpy(toBeEncryptBytes, (unsigned char *)input, inputLength);
    
    //填充数据
    for (int i = 0; i < padding; i++) {
        toBeEncryptBytes[inputLength + i] = padding;
    }
    toBeEncryptBytes[needInputLength] = '\0';

    //加密后的数据长度
    unsigned char *output = (unsigned char *)calloc(needInputLength, sizeof(unsigned char));

    //设置加密的key,并初始化
    mbedtls_aes_setkey_enc(&aes, (unsigned char*)key, keyLength * 8);

    //加密数据
    mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, needInputLength, iv, toBeEncryptBytes, output);
    
    char outputHex[ 2 * needInputLength + 1];
    memset(outputHex, 0, 2 * needInputLength + 1);

    bytes2HexStr(outputHex, output, needInputLength);

    printf("aesEncode(%s, %s)=%s\n", toBeEncryptBytes, key, outputHex);

    if (NULL != toBeEncryptBytes) {
        free(toBeEncryptBytes);
        toBeEncryptBytes = NULL;
    }

    return output;
}
Exemplo n.º 12
0
static int aes_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length,
        unsigned char *iv, const unsigned char *input, unsigned char *output )
{
    return mbedtls_aes_crypt_cbc( (mbedtls_aes_context *) ctx, operation, length, iv, input,
                          output );
}
Exemplo n.º 13
0
bool CVolumeWiiCrypted::CheckIntegrity() const
{
  // Get partition data size
  u32 partSizeDiv4;
  Read(m_VolumeOffset + 0x2BC, 4, (u8*)&partSizeDiv4, false);
  u64 partDataSize = (u64)Common::swap32(partSizeDiv4) * 4;

  u32 nClusters = (u32)(partDataSize / 0x8000);
  for (u32 clusterID = 0; clusterID < nClusters; ++clusterID)
  {
    u64 clusterOff = m_VolumeOffset + m_dataOffset + (u64)clusterID * 0x8000;

    // Read and decrypt the cluster metadata
    u8 clusterMDCrypted[0x400];
    u8 clusterMD[0x400];
    u8 IV[16] = {0};
    if (!m_pReader->Read(clusterOff, 0x400, clusterMDCrypted))
    {
      NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read metadata", clusterID);
      return false;
    }
    mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, 0x400, IV, clusterMDCrypted,
                          clusterMD);

    // Some clusters have invalid data and metadata because they aren't
    // meant to be read by the game (for example, holes between files). To
    // try to avoid reporting errors because of these clusters, we check
    // the 0x00 paddings in the metadata.
    //
    // This may cause some false negatives though: some bad clusters may be
    // skipped because they are *too* bad and are not even recognized as
    // valid clusters. To be improved.
    bool meaningless = false;
    for (u32 idx = 0x26C; idx < 0x280; ++idx)
      if (clusterMD[idx] != 0)
        meaningless = true;

    if (meaningless)
      continue;

    u8 clusterData[0x7C00];
    if (!Read((u64)clusterID * 0x7C00, 0x7C00, clusterData, true))
    {
      NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read data", clusterID);
      return false;
    }

    for (u32 hashID = 0; hashID < 31; ++hashID)
    {
      u8 hash[20];

      mbedtls_sha1(clusterData + hashID * 0x400, 0x400, hash);

      // Note that we do not use strncmp here
      if (memcmp(hash, clusterMD + hashID * 20, 20))
      {
        NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: hash %d is invalid", clusterID,
                   hashID);
        return false;
      }
    }
  }

  return true;
}
Exemplo n.º 14
0
/**
* Block symmetric ciphers.
* Please note that linker-override is possible, but dynamic override is generally
*   preferable to avoid clobbering all symmetric support.
*
* @param uint8_t* Buffer containing plaintext.
* @param int      Length of plaintext.
* @param uint8_t* Target buffer for ciphertext.
* @param int      Length of output.
* @param uint8_t* Buffer containing the symmetric key.
* @param int      Length of the key, in bits.
* @param uint8_t* IV. Caller's responsibility to use correct size.
* @param Cipher   The cipher by which to encrypt.
* @param uint32_t Options to the optionation.
* @return true if the root function ought to defer.
*/
int __attribute__((weak)) wrapped_sym_cipher(uint8_t* in, int in_len, uint8_t* out, int out_len, uint8_t* key, int key_len, uint8_t* iv, Cipher ci, uint32_t opts) {
  if (cipher_deferred_handling(ci)) {
    // If overriden by user implementation.
    return _sym_overrides[ci](in, in_len, out, out_len, key, key_len, iv, ci, opts);
  }
  int8_t ret = -1;
  switch (ci) {
    #if defined(MBEDTLS_AES_C)
      case Cipher::SYM_AES_256_CBC:
      case Cipher::SYM_AES_192_CBC:
      case Cipher::SYM_AES_128_CBC:
        {
          mbedtls_aes_context ctx;
          if (opts & OP_ENCRYPT) {
            mbedtls_aes_setkey_enc(&ctx, key, (unsigned int) key_len);
          }
          else {
            mbedtls_aes_setkey_dec(&ctx, key, (unsigned int) key_len);
          }
          ret = mbedtls_aes_crypt_cbc(&ctx, _cipher_opcode(ci, opts), in_len, iv, in, out);
          mbedtls_aes_free(&ctx);
        }
        break;
    #endif

    #if defined(MBEDTLS_RSA_C)
      case Cipher::ASYM_RSA:
        {
          mbedtls_ctr_drbg_context ctr_drbg;
          mbedtls_ctr_drbg_init(&ctr_drbg);
          size_t olen = 0;
          mbedtls_pk_context ctx;
          mbedtls_pk_init(&ctx);
          if (opts & OP_ENCRYPT) {
            ret = mbedtls_pk_encrypt(&ctx, in, in_len, out, &olen, out_len, mbedtls_ctr_drbg_random, &ctr_drbg);
          }
          else {
            ret = mbedtls_pk_decrypt(&ctx, in, in_len, out, &olen, out_len, mbedtls_ctr_drbg_random, &ctr_drbg);
          }
          mbedtls_pk_free(&ctx);
        }
        break;
    #endif

    #if defined(MBEDTLS_BLOWFISH_C)
      case Cipher::SYM_BLOWFISH_CBC:
        {
          mbedtls_blowfish_context ctx;
          mbedtls_blowfish_setkey(&ctx, key, key_len);
          ret = mbedtls_blowfish_crypt_cbc(&ctx, _cipher_opcode(ci, opts), in_len, iv, in, out);
          mbedtls_blowfish_free(&ctx);
        }
        break;
    #endif

    #if defined(WRAPPED_SYM_NULL)
      case Cipher::SYM_NULL:
        memcpy(out, in, in_len);
        ret = 0;
        break;
    #endif

    default:
      break;
  }
  return ret;
}