-
-
Save CryptoDed/1b34e4bfcd093afaf0677eaa3895bd4b to your computer and use it in GitHub Desktop.
[--] | |
name=CSP-trial-key | |
salt=2256, 1381 | |
gost=1 | |
# known S1=[1702 1223 1976 3333 1684 3478] (встречается в начальных проверках, забанены?) | |
# 3.6/Broken salt? | |
# 2256, 1381 - trial key for csp | |
# 4654, 2359 | |
# 6572, 2031 | |
# 2365, 2021 | |
# 9594, 1034 | |
# 6572, 7736 | |
# 2576, 5221 | |
# 1973, 2006 | |
[05] | |
name=Office Signature | |
pack=05 | |
version=2.0 | |
salt=7632, 1390 | |
key={F8DCE222-4388-468D-A174-97669AA8C3FF} | |
trial={232B5FEB-32ED-4DD4-8442-2BF332658306} | |
[051] | |
name=Office Signature | |
pack=05 | |
version=1.0 | |
salt=7632, 1390 | |
key={8CFC80FA-6524-437E-854A-0AF1790FE280} | |
trial={EC771014-A78A-41CE-B0EB-5D5B33595C83} | |
[0A] | |
name=OCSP Client | |
pack=0A | |
version=2.0 | |
salt=6283, 4181 | |
key=SOFTWARE/Crypto Pro/OCSPAPI/2.0 | |
trial={FF144EF4-D14F-4C6D-B297-21E4663678B1} | |
[0A1] | |
name=OCSP Client | |
pack=0A | |
version=1.0 | |
salt=6283, 4181 | |
key=SOFTWARE/Crypto Pro/OCSPAPI | |
trial={2BE5662D-0A5D-45BA-B896-794DE4DD844A} | |
[0C] | |
name=OCSP Server | |
pack=0C | |
salt=4681, 9468 | |
key={061EBE07-B821-4AE6-A9D2-343199B2FA8B} | |
trial={AFC33692-B993-4326-8A60-808AAE67D2E8} | |
[0D] | |
name=OCSP SDK | |
pack=0D | |
salt=3466, 9024 | |
key={42AD319A-FC11-4593-8516-AD9DC7BCE01D} | |
trial={64B4C84F-E7EE-4F9A-B9DA-020658EBCF2A} | |
[1P] | |
name=IPsec | |
pack=1P | |
salt=8465, 7712 | |
key={B64F15DF-B037-4B8E-994A-8A7F16AE559D} | |
trial={68CEEFA3-51D3-4C4F-84DE-9D4D87BF4E1C} | |
[36] | |
name=CSP | |
pack=36 | |
salt=5097, 3409 | |
gost=1 | |
version=3.6 | |
subver=00 | |
haveserver=1 | |
haveunixts=1 | |
extra={247F4CC0-723C-40A5-9A38-E2E2C24DEB46} | |
extra2={CFB5BEA5-3AAB-425C-9589-33D033A24CE6} | |
key={54A08450-B343-40B0-924E-68F031450996} | |
trial={39609410-04E2-4AFC-BCF8-34CA429798CF} | |
# Extra GUID's for CSP 3.6 - 3636XX... | |
{54A08450-B343-40B0-924E-68F031450996}=00, CSP | |
{E7A8D169-61E2-41B6-BE7D-FBADFD6D65AE}=0A | |
{943BB6AF-3021-48E8-B23D-C4EF1F0E4ED1}=0T, Gemalto CSP | |
{6EC0014E-976B-46F3-AC7D-3F992B4AE9B5}=0G, eToken GOST CSP | |
{188F4791-B9A8-4DBF-8D55-68042F74E9FC}=0U, УЭК CSP | |
{8CBFA1BD-0151-4FBC-99AB-FBAAC4B4E09E}=0M, Магистра CSP | |
{BE3CE2FE-08AB-4711-93C2-26DFE2BD7273}=0R, Рутокен CSP | |
{EFAFF4D1-B76E-4C0C-9B7F-0BDF00CD5AFC}=0E, eToken CSP | |
[36A] | |
name=CSP 0A? | |
pack=36 | |
salt=5097, 3409 | |
gost=1 | |
version=3.6 | |
haveserver=1 | |
haveunixts=1 | |
key={E7A8D169-61E2-41B6-BE7D-FBADFD6D65AE} | |
subver=0A | |
[36T] | |
name=Gemalto CSP | |
pack=36 | |
salt=5097, 3409 | |
gost=1 | |
version=3.6 | |
haveserver=1 | |
haveunixts=1 | |
key={943BB6AF-3021-48E8-B23D-C4EF1F0E4ED1} | |
subver=0T | |
[36U] | |
name=UEC CSP | |
pack=36 | |
salt=5097, 3409 | |
gost=1 | |
version=3.6 | |
haveserver=1 | |
haveunixts=1 | |
key={188F4791-B9A8-4DBF-8D55-68042F74E9FC} | |
subver=0U | |
[36M] | |
name=Magistra CSP | |
pack=36 | |
salt=5097, 3409 | |
gost=1 | |
version=3.6 | |
haveserver=1 | |
haveunixts=1 | |
key={8CBFA1BD-0151-4FBC-99AB-FBAAC4B4E09E} | |
subver=0M | |
[36R] | |
name=ruToken CSP | |
pack=36 | |
salt=5097, 3409 | |
gost=1 | |
version=3.6 | |
haveserver=1 | |
haveunixts=1 | |
key={BE3CE2FE-08AB-4711-93C2-26DFE2BD7273} | |
subver=0R | |
[36E] | |
name=eToken CSP | |
pack=36 | |
salt=5097, 3409 | |
gost=1 | |
version=3.6 | |
haveserver=1 | |
haveunixts=1 | |
key={EFAFF4D1-B76E-4C0C-9B7F-0BDF00CD5AFC} | |
subver=0E | |
[39] | |
name=CSP | |
pack=39 | |
salt=8655, 7915 | |
gost=1 | |
version=3.9 | |
haveserver=1 | |
haveunixts=1 | |
extra={54A08450-B343-40B0-924E-68F031450996} | |
key={39D25A86-A5E6-42FC-9C8F-EFA4C138B08C} | |
trial={E1C6F5FD-77A1-4F3C-B53E-F2479EFC0FC8} | |
[40] | |
name=CSP | |
pack=40 | |
salt=3462, 1107 | |
gost=1 | |
version=4.0 | |
haveserver=1 | |
haveunixts=1 | |
key={407E5BA7-6406-40BF-A4DC-3654B8F584C1} | |
trial={C8B655BB-28A0-4BB6-BDE1-D0826457B2DF} | |
[403] | |
name=CSP | |
pack=40 | |
version=3.9 | |
salt=3462, 1107 | |
gost=1 | |
haveserver=1 | |
haveunixts=1 | |
extra={247F4CC0-723C-40A5-9A38-E2E2C24DEB46} | |
key={38C0732A-2E38-4BF5-B673-57449DC80CA1} | |
trial={4448EEC3-836F-4D11-B72D-839C5C79702C} | |
[AF] | |
name=SSF | |
pack=AF | |
salt=8677, 4860 | |
key={B494FFDD-E4D9-4484-8A17-3FC728C7A32F} | |
trial={CA1B001E-6B16-4E11-8479-55D4A01DD804} | |
[CD] | |
name=CSP | |
pack=CD | |
version=3.0 | |
salt=8245, 7239 | |
[D5] | |
name=DSS | |
pack=D5 | |
salt=4129, 4357 | |
[EF] | |
name=EFS | |
pack=EF | |
version=2.0 | |
salt=7052, 2494 | |
key={368F645E-3059-4DE5-B6D7-BCFE55A8032D} | |
trial={DE4BF2E9-C129-4E88-85DB-4B7526844631} | |
[EF1] | |
name=EFS | |
pack=EF | |
version=1.0 | |
salt=6963, 8724 | |
[EX] | |
name=EX? | |
pack=EX | |
salt=9073, 2534 | |
[HC] | |
name=.NET (client) | |
pack=HC | |
salt=8011, 8654 | |
key={F2F88A77-F7E6-4C9E-9C67-CB1855C62B45} | |
trial={EB3462F5-EF6A-4C62-AEC2-6FB1E4AE1E15} | |
[HH] | |
name=.NET (serv) | |
pack=HH | |
salt=2736, 4496 | |
key={F2F88A77-F7E6-4C9E-9C67-CB1855C62B45} | |
trial={EB3462F5-EF6A-4C62-AEC2-6FB1E4AE1E15} | |
[NY] | |
name=Sig.Check.Service | |
pack=NY | |
salt=6327, 5549 | |
key={BA4B3CCF-2558-4367-BAA4-D04B006A6BD1} | |
trial={F81D7574-E7B6-42c3-9735-86F47AF5EE4E} | |
[P0] | |
name=Tool.CryptCP | |
pack=P0 | |
salt=6457, 9034 | |
gost=1 | |
haveunixts=2 | |
key={23227C2E-F9E2-22E4-92C2-11215C328816}/ThreadingModel | |
trial={EG1EBFG3-B399-22E2-9798-117119C1F6E3} | |
[PD] | |
name=PDF | |
pack=PD | |
version=1.6 | |
salt=3845, 3409 | |
key={85CE021C-3982-446B-91D0-47CCFFE1BE4D} | |
trial={AC727718-838B-4C0C-976C-A34D432A0480} | |
[PD1] | |
name=PDF | |
pack=PD | |
version=1.4 | |
salt=3845, 3409 | |
key={FEB8699B-98F0-4520-8253-95CD621B99BC} | |
trial={03299E61-701D-488D-88E4-043A912790B9} | |
[RP] | |
name=Revocation.Prov | |
pack=RP | |
version=2.0 | |
salt=9623, 1985 | |
extra2={37ACCB12-7B89-4FDB-9DC3-A77A388D493C} | |
key=SOFTWARE/Crypto Pro/RP/2.0 | |
trial={2459B744-3F27-4962-9AE2-E2C2FC07D893} | |
[RP1] | |
name=Revocation.Prov | |
pack=RP | |
version=1.0 | |
salt=9623, 1985 | |
extra2={37ACCB12-7B89-4FDB-9DC3-A77A388D493C} | |
key=SOFTWARE/Crypto Pro/RP | |
trial={15C59642-589A-4B38-ABED-391C9823DF43} | |
[TA] | |
name=TSP Client | |
pack=TA | |
version=2.0 | |
salt=1565, 4393 | |
key=SOFTWARE/Crypto Pro/TSPAPI/2.0 | |
trial={D7B0E69E-44C2-4526-A1F2-F9DB46EE4613} | |
[TA1] | |
name=TSP Client | |
pack=TA | |
version=1.0 | |
salt=1565, 4393 | |
key=SOFTWARE/Crypto Pro/TSPAPI | |
trial={A18E9B97-4A50-4748-BD7F-0C6B04A61D99} | |
[TD] | |
name=TSP SDK | |
pack=TD | |
version=1.0 | |
salt=7342, 3485 | |
key={E756B772-F853-46C7-ACA7-43082678DF96} | |
trial={01764ACF-FDB2-4A4C-9EB3-8D1A860E8234} | |
[TS] | |
name=TSP Server | |
pack=TS | |
version=2.0 | |
salt=3485, 7890 | |
key={F0740A19-6AAC-46B2-8413-6AFF70562B2C} | |
trial={E3F1AAD0-B7FC-48F7-8BBE-000095E3E11C} | |
[WL] | |
name=WL | |
pack=WL | |
salt=3478, 4857 | |
haveunixts=1 | |
trial={FA868689-9029-49D5-AF19-8185CE427ED0} | |
[WS] | |
name=WS | |
pack=WS | |
salt=8108, 3964 | |
haveunixts=1 | |
trial={FA868689-9029-49D5-AF19-8185CE427ED0} |
#!/usr/bin/perl | |
package CPRO; | |
use strict; | |
use 5.010; | |
use Digest::SHA qw(sha1); | |
use Digest::GOST::CryptoPro qw(gost); | |
use Encode qw(from_to); | |
#use utf8; | |
use Config::IniFiles; | |
my $ini=Config::IniFiles->new(-file=>"cpro.ini"); | |
# Бинарную строку преобразуем в Base32 | |
# код цинично утащен из MIME::Base32 | |
sub encode{local $_ = shift @_; | |
$_=unpack('b*', $_); | |
s/(.....)/${1}000/g; | |
$_=pack('b*', $_); | |
tr/\0-\37/0123456789ABCDEFGHKLMNPQRTUVWXYZ/; | |
$_} | |
# Base32 преобразуем в бинарную строку | |
sub decode{local $_ = uc(shift @_); | |
tr/0123456789ABCDEFGHKLMNPQRTUVWXYZ -/\0-\37/d; | |
$_=unpack('b*', $_); | |
s/(.....)000/$1/g; | |
pack('b*', $_)} | |
sub ToHex($;$){my ($s,$l)=@_; | |
if ('ARRAY' eq ref $s){$l//=0+@$s; | |
my $r=0;my $m=1;foreach my $n (@$s){$r+=$n*$m;$m*=32}$s=$r} | |
$l//=1; | |
my $r=encode(pack'I',$s);$r=substr($r.('0'x$l),0,$l) if $l!=length $r;$r} | |
# чудовищный шЫыыфр для даты устранвки | |
sub prot($;$) {my ($src,$step)=@_; $step||=10; pack 'C*', map $_+$step, unpack 'C*', $src} | |
sub unprot($;$){my ($src,$step)=@_; $step||=10; prot($src,-$step)} | |
sub Format($){my $a=uc shift;warn "Chars in key removed" if $a=~s/[^0-9A-Z]//g;$a=~s/.....(?!$)/$&-/g;$a} | |
# Солёный хеш | |
sub Hash($;$$){my ($CODE,$prod,$a_isGost)=@_; | |
$prod=substr($CODE,0,2) if !defined $prod; | |
if (!$ini->SectionExists($prod)){warn "Ой, что это? $prod??";return} | |
my $salt=$ini->val($prod,'salt'); | |
if (!defined $salt){warn "$prod/".$ini->val($prod,'name')." - К сожалению, с этим продуктом не всё так просто";return} | |
my ($S1,$S2)=split/,\s*/,$salt; | |
my $isGost=$ini->val($prod,'gost'); | |
$isGost=$a_isGost if defined $a_isGost; | |
from_to($CODE,'UTF-8','UTF-16LE') if ! ($isGost & 2); | |
my $string=pack('Ia*I',$S1,$CODE,$S2); | |
#say unpack 'H*',$string; | |
my $dig=($isGost & 1)? gost($string) : sha1($string); | |
return encode($dig) if !($isGost & 4); | |
return $dig} | |
# проверить ключик и поправить его. Возвращает "полный хеш". | |
sub Match($;@){my ($CODE)=@_; | |
$CODE=~y/-//d;$CODE=uc $CODE; | |
$CODE=substr($CODE.('0'x25),0,25) if length $CODE<25; | |
my $BASE=substr($CODE,0,17); | |
my $SIGN=substr($CODE,17,8); | |
my $hash=Hash($BASE); | |
return if !defined $hash; | |
my $XSIGN=substr($hash,0,8); | |
if ($SIGN ne $XSIGN){say $BASE.$XSIGN."\t(corrected)"} | |
else {say $CODE} | |
$hash} | |
# Просто исправить то, что дали в качесте материала ключа. Возвращает поправленный ключик | |
# первый аргумент - сам ключ или его начало | |
# второй аргумент - "случайная часть" | |
# третий аргумент - признак триальности. | |
sub Gen($;$$){my ($CODE,$RAND,$TRIAL)=@_; | |
$CODE=~y/-//d;$CODE=uc $CODE; | |
$CODE=substr($CODE.('0'x25),0,25) if length $CODE<25; | |
substr($CODE,9,8,substr(('0'x8).uc $RAND,-8)) if defined $RAND; | |
substr($CODE,8,1,substr(0+$TRIAL,-1)) if defined $TRIAL; | |
my $BASE=substr($CODE,0,17); | |
my $hash=Hash($BASE); | |
return if !defined $hash; | |
my $XSIGN=substr($hash,0,8); | |
say $BASE.$XSIGN; | |
$BASE.$XSIGN} | |
1; | |
__END__ | |
#25*32+1=801 mon max trial (T1) | |
#0123456789ABCDEF | |
#GHKLMNPQRTUVWXYZ | |
##0123456789012345678901234 | |
##PPVV--TMm--SLLL--HHHHHHHH | |
##PPVVAATBBCCCTTT--HHHHHHHH | |
# AA = Word_4_2 | |
# T = KeyType | |
# BB = TrialTime (month) | |
# CCC = | |
# TTT = Time (year-2006, mon, day) |
#include "eid.h" | |
#pragma comment ( lib, "advapi32.lib" ) | |
#define ERR(X) (throw((LPVOID)(X)),0) | |
typedef struct { PUBLICKEYSTRUC kh; DWORD len;BYTE d[SHA1_LEN]; } KEY_INFO; | |
static KEY_INFO key_info = { | |
key_info.kh.bType=PLAINTEXTKEYBLOB, // PLAINTEXTKEYBLOB=8 | |
key_info.kh.bVersion=CUR_BLOB_VERSION, // CUR_BLOB_VERSION=2 | |
key_info.kh.reserved=0, | |
key_info.kh.aiKeyAlg=CALG_RC2, // CALG_RC2=0x6602 | |
key_info.len=SHA1_LEN, | |
}; | |
static const HMAC_INFO hi = {CALG_SHA1}; // CALG_SHA1=0x8004 | |
static const BYTE salt[]="mysmartlogon.com"; | |
bool eid_hash(LPCBYTE data, size_t dlen, LPBYTE hash, size_t hashlen){ | |
HCRYPTKEY hKey=NULL; | |
HCRYPTHASH hHash=NULL, hmac = NULL; | |
HCRYPTPROV hProv=NULL; | |
memset(hash, 0, hashlen); | |
bool ret = 0; | |
try { | |
CryptAcquireContext(&hProv, 0, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) || ERR(CryptAcquireContext); // PROV_RSA_FULL=1, CRYPT_VERIFYCONTEXT=0xF0000000, MS_ENHANCED_PROV="Microsoft Enhanced Cryptographic Provider v1.0" | |
CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash) || ERR(CryptCreateHash);// CALG_SHA1=0x8004 | |
CryptHashData(hHash, (LPCBYTE)&salt, sizeof(salt) - 1, 0) || ERR(CryptHashData);// size=16 | |
CryptGetHashParam(hHash, HP_HASHVAL, key_info.d, &key_info.len, 0) || ERR(CryptGetHashParam);// HP_HASHVAL=2 | |
CryptImportKey(hProv, (LPCBYTE)&key_info, sizeof(key_info), 0, CRYPT_IPSEC_HMAC_KEY, &hKey) || ERR(CryptImportKey); // CRYPT_IPSEC_HMAC_KEY=0x100, size=32 | |
CryptCreateHash(hProv, CALG_HMAC, hKey, 0, &hmac) || ERR(CryptCreateHash);// CALG_HMAC=0x8009 | |
CryptSetHashParam(hmac, HP_HMAC_INFO, (LPCBYTE)&hi, 0) || ERR(CryptSetHashParam);// HP_HMAC_INFO=5 | |
CryptHashData(hmac, data, (DWORD)dlen, 0) || ERR(CryptHashData); | |
CryptGetHashParam(hmac, HP_HASHVAL, hash, &key_info.len, 0) || ERR(CryptGetHashParam);// HP_HASHVAL=2 | |
ret = 1; | |
} | |
catch (LPVOID func) { | |
perror(GetName(func)); | |
ret = 0; | |
} | |
hKey && CryptDestroyHash(hKey); | |
hmac && CryptDestroyHash(hmac); | |
hHash && CryptDestroyHash(hHash); | |
hProv && CryptReleaseContext(hProv, 0); | |
return ret; | |
} | |
#define ALG_SID_GOST 30 | |
#define CALG_GOST (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_GOST) | |
#define PROV_CRYPTOPRO 75 | |
bool cphash(LPCBYTE data, size_t dlen, bool isGost, UINT32 S1, UINT32 S2, LPBYTE hash, LPDWORD len) { | |
HCRYPTHASH hHash = NULL; | |
HCRYPTPROV hProv = NULL; | |
memset(hash, 0, *len); | |
bool ret = false; | |
try { | |
CryptAcquireContext(&hProv, 0, isGost? NULL : MS_ENHANCED_PROV, isGost? PROV_CRYPTOPRO : PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) || ERR(CryptAcquireContext); // PROV_RSA_FULL=1, CRYPT_VERIFYCONTEXT=0xF0000000, MS_ENHANCED_PROV="Microsoft Enhanced Cryptographic Provider v1.0" | |
CryptCreateHash(hProv, isGost? CALG_GOST : CALG_SHA1, 0, 0, &hHash) || ERR(CryptCreateHash);// CALG_SHA1=0x8004, CALG_GOST=0x801E | |
CryptHashData(hHash, (LPCBYTE)&S1, sizeof(S1), 0) || ERR(CryptHashData); | |
CryptHashData(hHash, data, (DWORD)dlen, 0) || ERR(CryptHashData); | |
CryptHashData(hHash, (LPCBYTE)&S2, sizeof(S2), 0) || ERR(CryptHashData); | |
CryptGetHashParam(hHash, HP_HASHVAL, hash, len, 0) || ERR(CryptGetHashParam);// HP_HASHVAL=2 | |
ret = true; | |
} | |
catch (LPVOID func) { | |
perror(GetName(func)); | |
ret = false; | |
} | |
hHash && CryptDestroyHash(hHash); | |
hProv && CryptReleaseContext(hProv, 0); | |
return ret; | |
} | |
LPSTR hex2str(LPCBYTE src, size_t len, LPSTR dst, size_t dst_len) { | |
if (len * 2 + 1 > dst_len) len = (dst_len - 1) / 2; | |
if (len <= 0) return NULL; | |
for (size_t i = 0; i < len; i++) | |
sprintf_s(dst + i * 2, 3, "%02X", src[i]); | |
return dst; | |
} | |
static const char MIME[] = "0123456789ABCDEFGHKLMNPQRTUVWXYZ"; | |
size_t MIME2BIN(LPCSTR src, size_t src_len, LPBYTE dst, size_t dst_len){ | |
if (dst_len<=0) return 0; | |
if (src_len<=0) src_len = strlen(src); | |
BYTE rest = 0; // счётчик битов | |
size_t pb = 0; // указатель на текущий байт на вывод | |
*dst = 0; | |
for (size_t i=0; i<src_len; i++) { | |
int s=toupper(src[i]); | |
if (!s) break; // EOS | |
LPCSTR m = strchr(MIME, s); | |
if (!m) continue; // non-mime character - skip it | |
s = (int)(m - MIME); | |
dst[pb] |= (BYTE) (s << rest); | |
rest += 5; // добавили 5 бит | |
if (rest >= 8) {// есть полные 8 бит | |
rest -= 8; | |
if (++pb >= dst_len) return pb; // буфер полон - аварийное завершение | |
dst[pb] = (BYTE)(s >> (5 - rest)); // "не влезший" кусок запихаем в следующий байт | |
} | |
} | |
if (rest > 0) pb++; // остался неполный байт - покажем что он есть | |
return pb; | |
} | |
size_t BIN2MIME(LPCBYTE src, size_t src_len, LPSTR dst, size_t dst_len) { | |
BYTE rest = 0; // счётчик битов | |
UINT buf = 0; // аккумулятор | |
size_t dptr = 0; // указатель на текущий символ на вывод | |
if (dst_len <= 0) return 0; | |
for (size_t i = 0; i < src_len && dptr < dst_len; i++) | |
for (buf |= src[i] << rest, rest += 8; // добавляем 8 бит в аккумулятор | |
dptr < dst_len && rest >= 5; // пока выходной буфер не кончился и у нас есть 5 бит для вывода | |
buf >>= 5, rest -= 5) // убираем 5 бит из аккумулятора | |
dst[dptr++] = MIME[buf & 31]; // выводим 5 бит | |
if (rest > 0 && dptr < dst_len) dst[dptr++] = MIME[buf]; // последний символ | |
if (dptr >= dst_len) dptr = dst_len - 1; // не влезли в буфер - обрезаем (авария) | |
dst[dptr] = 0; // EOS | |
return dptr; | |
} |
#pragma once | |
#include <windows.h> | |
#include <stdio.h> | |
#include <wincrypt.h> | |
#define SHA1_LEN 20 | |
#define GOST_LEN 32 | |
LPCSTR GetName(LPVOID ptr); // get name of import symbol | |
bool eid_hash(LPCBYTE data, size_t dlen, LPBYTE hash, size_t hashlen = SHA1_LEN); | |
bool cphash(LPCBYTE data, size_t dlen, bool isGost, UINT32 S1, UINT32 S2, LPBYTE hash, LPDWORD len); | |
LPSTR hex2str(LPCBYTE src, size_t len, LPSTR dst, size_t dst_len); | |
size_t MIME2BIN(LPCSTR src, size_t src_len, LPBYTE dst, size_t dst_len); | |
size_t BIN2MIME(LPCBYTE src, size_t src_len, LPSTR dst, size_t dst_len); | |
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_2_0(LPSTR, hex2str, LPCBYTE, src, size_t, src_len, CHAR, dst); | |
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_2_0(size_t, MIME2BIN, LPCSTR, src, size_t, src_len, BYTE, dst); | |
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_2_0(size_t, BIN2MIME, LPCBYTE, src, size_t, src_len, CHAR, dst); |
#include "eid.h" | |
static PIMAGE_IMPORT_DESCRIPTOR adv = NULL; | |
#define RVA(X) (LPVOID)(((BYTE*)hm)+(UINT)X) | |
LPCSTR GetName(LPVOID ptr) { | |
HMODULE hm = GetModuleHandle(NULL); | |
if (adv == NULL) { | |
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)RVA(0); | |
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)RVA(dos->e_lfanew); | |
PIMAGE_DATA_DIRECTORY imp; | |
if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) imp = ((PIMAGE_NT_HEADERS32)nt)->OptionalHeader.DataDirectory; | |
else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) imp = ((PIMAGE_NT_HEADERS64)nt)->OptionalHeader.DataDirectory; | |
else return NULL; | |
adv = (PIMAGE_IMPORT_DESCRIPTOR)RVA(imp[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); | |
while (true) { | |
if (!adv->Name) { | |
adv = NULL; | |
return NULL; | |
} | |
LPCSTR Name = (LPCSTR)RVA(adv->Name); | |
if (!_strcmpi(Name, "ADVAPI32.dll")) break; | |
adv++; | |
} | |
} | |
LPVOID * ptrs = (LPVOID *)RVA(adv->FirstThunk); | |
LPVOID * imps = (LPVOID *)RVA(adv->OriginalFirstThunk); | |
for (int i = 0;ptrs[i];i++) { | |
if (ptrs[i] == ptr) | |
return (LPCSTR)RVA(imps[i]) + 2; | |
} | |
return NULL; | |
} |
use 5.010; | |
use CPRO; | |
say CPRO::Gen('PD20PP000VABAC2A9'); |
#include "eid.h" | |
#include <stdarg.h> | |
bool TestCHash(LPCWCHAR to_hash, size_t hash_sz, LPCSTR must_have, UINT S1, UINT S2, bool isGost) { | |
BYTE hb[GOST_LEN]; | |
char tmp[GOST_LEN * 2 + 1]; | |
DWORD sz = sizeof(hb); | |
cphash((LPCBYTE)to_hash, (hash_sz-1)*sizeof(WCHAR), isGost, S1, S2, hb, &sz); | |
printf("For string: %ls hash: %u/%s\n", to_hash, sz, hex2str(hb, sz, tmp)); | |
size_t cnt = BIN2MIME(hb, sz, tmp); | |
printf("Mime: %zd/%s\nShould: %s\n", cnt, tmp, must_have); | |
return true; | |
} | |
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_4(bool, TestCHash, const WCHAR, to_hash, LPCSTR, must_have, UINT, S1, UINT, S2, bool, isGost); | |
bool TestEID(LPCBYTE bb, size_t sz) { | |
BYTE hb[SHA1_LEN]; | |
char tmp[SHA1_LEN * 2 + 1]; | |
bool res = eid_hash(bb, sz, hb, sizeof(hb)); | |
printf("The hash %s: %s\n", res ? "is" : "can", hex2str(hb, sizeof(hb), tmp)); | |
return res; | |
} | |
bool TestEID(LPCSTR bb, size_t sz) { return TestEID((LPCBYTE)bb, sz - 1); } | |
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_0(bool, TestEID, const BYTE, to_hash); | |
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_0(bool, TestEID, const CHAR, to_hash); | |
bool TestMIME(LPCSTR msg, size_t sz) { | |
BYTE hb[1024]; | |
char tmp[2048]; | |
size_t cnt = MIME2BIN(msg, sz-1, hb); | |
printf("For string: %s -> %zd/%s\n", msg, cnt, hex2str(hb, cnt, tmp)); | |
cnt=BIN2MIME(hb, cnt, tmp); | |
printf("Backed: %zd/%s\n", cnt, tmp); | |
return true; | |
} | |
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_0(bool, TestMIME, const CHAR, msg); | |
static const BYTE bb[] = { 0x03,0x00, 0x33,0x33, 0x33,0x33, 0x33,0x33, 0x33,0x33 }; | |
int main() { | |
// процедуры для mysmartlogons | |
TestEID(bb); // подпись ключа (последние 4 символа ключа - первые 2 байта хеша) | |
TestEID("00331-10000-00001-AA161"); // Windows Product ID - активация "онлайн". | |
// процедуры для крипто про | |
// проверка декодировки триального ключа | |
TestMIME("000000WATDE1ETG31LW7UYXGCKU46LYB0QG2MZKWF5ER03LTXFMQ35Q2NR39DBGE0"); | |
// проверка подписи ключа | |
TestCHash(L"0510PP000VA9AC2A9", "ZHCMLLUB", 7632, 1390, false); | |
// проверка подписи триального ключа | |
TestCHash(L"000000WATDE1E", "TG31LW7UYXGCKU46LYB0QG2MZKWF5ER03LTXFMQ35Q2NR39DBGE0", 2256, 1381, true); | |
return 0; | |
} |
Добавил функцию - которая по адресу функции в advapi.dll даёт ссылку на её имя из таблицы импорта экзешника.
Используется в обработчике эксцепшенов в примере.
формирование триальных ключей:
my $tm=time;
my ($d,$m,$y)=(localtime $tm)[3,4,5];
$m++;$y-=100;
my $tf1=sprintf "%02u%02u%02u", $d,$m,$y; # 051016
my $tf2=sprintf "%04u-%02u-%02u", $y+2000, $m, $d; # 2016-10-05
my $et1=CPRO::prot($tf1,+10);
my $et2=CPRO::prot($tf2,-20);
my $et3=CPRO::encode(pack'IN',0,$tm);
my $tri3=$et3.CPRO::Hash($et3,'--'); # универсальный триал для линейки CSP
my $keytime=CPRO::ToHex([$y-6,$m,$d]); # время для записи в нужное поле ключика
given ($xs->{haveunixts}){ # Для продукта $s получаем триальный ключ:
when (1) {$ft=$tf2;$tri=$tri3}
when (2) {$ft=$tf2;@tri=unpack 'C*', $et2.CPRO::Hash($tf2, $s, 1+2+4)} # isGost + noUTF16 + noBase32
default {$ft=$tf1;$tri=$et1.CPRO::Hash($et1,$s eq 'HH'? 'HC' : $s)}#;@tri='#'.$tri}
}
Реализация кейгена на перле и на С.
На С ещё кейген и "онлайн активатор" для EID с сайта mysmartlogon (не обращайте на него внимания - там HMAC).
Ключи кпро состоят из кода продукта (2 символа), номера версии (2 символа), кода субпродукта (когда применим - иначе рандом), код ключа (1 символ: триал=3, безлимит=0), срока действия ключа (2 символа - число месяцев, 00=безлимит), флагов (3 символа: рандом, но иногда K в третьем символе=серверный ключ), и даты начала/конца действия ключа (3 символа: год-2006, месяц, день).
Числа кодирутся "их" Base32: 0=0, 31=Z.
После ключа идёт кусок хеш-суммы.
##0123456789012345678901234
##PPVVAATBBCCCTTTRRHHHHHHHH
PP = prod
VV = ver
AA = sub-prod/rand
T = KeyType (3=trial)
BB = TrialTime (month, 00=unlim)
CCC = flags/rand
TTT = Time (year-2006, mon, day)
RR=rand
HHH.. - 8 first bytes of hash
Минусы через 5 символов нужны "для красоты" вывода - все продукты их игнорируют и убирают перед проверкой.
О хеш сумме. В общем виде это Base32 закодированный солёный хеш. Для большинства продуктов хеш это SHA1, для некоторых (в основном линейки ЦСП - в ini файле отмечены gost=1) это ГОСТ (нужен установленный криптопро для вычисления).
HASH=BASE32(SHA1(S1+KEY+S2))
S1 и S2 это uint32 уникальные для продукта (иногда и субпродукта).
KEY имеет хитрость - он WCHAR (для аски символов - после каждого байта символа идёт байт 0).
Например для продукта PDF 2.0 хотим хеш ключика: PD20PP000VABAC2A9
видим ini секцию (аналогично 1.6 или 1.4):
[PD]
name=PDF
pack=PD
version=2.0
salt=3845, 3409
Значит хешируем SHA1, S1=3845, S2=3409
SHA1( 050f0000 50004400320030005000500030003000300056004100420041004300320041003900 510d0000 ) =
d700968b0da44f6413ad0f7cf3369612804a8cdd
Потом кодируем эту сумму в BASE32 (по строке замены 0123456789ABCDEFGHKLMNPQRTUVWXYZ)
и берём первые 8 символов (должны получиться Q60CT5P1).
Для триальных ключей алгоритм похож, только для продуктов цсп берётся гост хеш и для триала используется одна и та же соль: S1=2256, S2=1381, а также используется unix-время (64-битное, старший байт первый) закодированное base32.
Для остальных берётся соль ключа продукта и время в формате DDMMYY - только символы "зашифрованы" прибавлением 10 (CHR(ASC(A)+10). 2 ноября 2016 =021116=:<;;;@. Расшифровать - вычесть из символов 10.
Для консольной утилиты кпро - триалключ другой и сдвиг "шифра" -20.
Время без измнения загоняется в хеш-функцию и полный base32 хеш добавляется в после штампа времени.
Триальные ключи они есть в ini файле ({EC77..} уникален для версий продукта, wow6432 нужен для 64-битной винды)
можно искать по этим адресам:
Без триалключа в реестре утилита управления лицензиями не показывает статус лицензий.
Ключи продукта пишутся в ветке:
222ECD8F8834D8641A477966A98A3CFF - это перекодированный guid {F8DCE222-4388-468D-A174-97669AA8C3FF}
Но лучше их помещать в файл *.lic (простой текстовый файл в папке %programdata%\Crypto pro - ключи продукта записаны построчно).