summaryrefslogtreecommitdiff
path: root/protocols/Steam/src/steam_crypt.cpp
blob: dd07cb7e32445870f2424a599f258f0e0f3c6ada (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "stdafx.h"

#pragma comment(lib, "crypt32.lib")

int CSteamProto::RsaEncrypt(const char *pszModulus, DWORD &exponent, const char *data, uint8_t *encryptedData, DWORD &encryptedSize)
{
	DWORD cchModulus = (DWORD)mir_strlen(pszModulus);
	int result;
	HCRYPTKEY phKey = 0;
	HCRYPTPROV hCSP = 0;

	__try {
		// convert hex string to byte array
		DWORD cbLen = 0, dwSkip = 0, dwFlags = 0;
		if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, nullptr, &cbLen, &dwSkip, &dwFlags)) {
			result = GetLastError();
			__leave;
		}

		// allocate a new buffer.
		mir_ptr<uint8_t> pbBuffer((uint8_t *)mir_alloc(cbLen));
		if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, pbBuffer, &cbLen, &dwSkip, &dwFlags)) {
			result = GetLastError();
			__leave;
		}

		// reverse byte array, because of microsoft
		for (int i = 0; i < (int)(cbLen / 2); ++i) {
			uint8_t temp = pbBuffer[cbLen - i - 1];
			pbBuffer[cbLen - i - 1] = pbBuffer[i];
			pbBuffer[i] = temp;
		}

		if (!CryptAcquireContext(&hCSP, nullptr, nullptr, PROV_RSA_AES, CRYPT_SILENT) &&
			!CryptAcquireContext(&hCSP, nullptr, nullptr, PROV_RSA_AES, CRYPT_SILENT | CRYPT_NEWKEYSET)) {
			result = GetLastError();
			__leave;
		}

		// Move the key into the key container.
		DWORD cbKeyBlob = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + cbLen;
		mir_ptr<uint8_t> pKeyBlob((uint8_t *)mir_alloc(cbKeyBlob));

		// Fill in the data.
		PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC *)pKeyBlob.get();
		pPublicKey->bType = PUBLICKEYBLOB;
		pPublicKey->bVersion = CUR_BLOB_VERSION;  // Always use this value.
		pPublicKey->reserved = 0;                 // Must be zero.
		pPublicKey->aiKeyAlg = CALG_RSA_KEYX;     // RSA public-key key exchange. 

		// The next block of data is the RSAPUBKEY structure.
		RSAPUBKEY *pRsaPubKey = (RSAPUBKEY *)(pKeyBlob + sizeof(PUBLICKEYSTRUC));
		pRsaPubKey->magic = 0x31415352; // RSA1 // Use public key
		pRsaPubKey->bitlen = cbLen * 8;  // Number of bits in the modulus.
		pRsaPubKey->pubexp = exponent; // Exponent.

		// Copy the modulus into the blob. Put the modulus directly after the
		// RSAPUBKEY structure in the blob.
		uint8_t *pKey = (uint8_t *)(((uint8_t *)pRsaPubKey) + sizeof(RSAPUBKEY));
		memcpy(pKey, pbBuffer, cbLen);

		// Now import public key	
		if (!CryptImportKey(hCSP, pKeyBlob, cbKeyBlob, 0, 0, &phKey)) {
			result = GetLastError();
			__leave;
		}

		DWORD dataSize = (DWORD)mir_strlen(data);

		// if data is not allocated just renurn size
		if (encryptedData == nullptr) {
			// get length of encrypted data
			if (!CryptEncrypt(phKey, 0, TRUE, 0, nullptr, &encryptedSize, dataSize))
				result = GetLastError();
			__leave;
		}

		// encrypt password
		memcpy(encryptedData, data, dataSize);
		if (!CryptEncrypt(phKey, 0, TRUE, 0, encryptedData, &dataSize, encryptedSize)) {
			result = GetLastError();
			__leave;
		}

		// reverse byte array again
		for (int i = 0; i < (int)(encryptedSize / 2); ++i) {
			uint8_t temp = encryptedData[encryptedSize - i - 1];
			encryptedData[encryptedSize - i - 1] = encryptedData[i];
			encryptedData[i] = temp;
		}
	}
	__finally
	{
		result = 0;
	};

	if (phKey)
		CryptDestroyKey(phKey);

	if (hCSP)
		CryptReleaseContext(hCSP, 0);

	return 0;
}