Skip to content

Instantly share code, notes, and snippets.

@CryptoDed
Last active February 1, 2017 22:30
Show Gist options
  • Save CryptoDed/1b34e4bfcd093afaf0677eaa3895bd4b to your computer and use it in GitHub Desktop.
Save CryptoDed/1b34e4bfcd093afaf0677eaa3895bd4b to your computer and use it in GitHub Desktop.
CPro
[--]
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;
}
@CryptoDed
Copy link
Author

CryptoDed commented Feb 1, 2017

Реализация кейгена на перле и на С.
На С ещё кейген и "онлайн активатор" для 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-битной винды)
можно искать по этим адресам:

[-HKEY_CURRENT_USER\SOFTWARE\Classes\Wow6432Node\CLSID\{EC771014-A78A-41CE-B0EB-5D5B33595C83}]
[-HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID\{EC771014-A78A-41CE-B0EB-5D5B33595C83}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{EC771014-A78A-41CE-B0EB-5D5B33595C83}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Wow6432Node\CLSID\{EC771014-A78A-41CE-B0EB-5D5B33595C83}\InprocServer32]
"InprocServer32"=";<;:;@NYNM41T0C4WT5Z6L3YA1790WP03X06T2"

Без триалключа в реестре утилита управления лицензиями не показывает статус лицензий.

Ключи продукта пишутся в ветке:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\222ECD8F8834D8641A477966A98A3CFF\InstallProperties]
"ProductID"="05201-K00K5-V3AB2-V3P71-URWWQ"

222ECD8F8834D8641A477966A98A3CFF - это перекодированный guid {F8DCE222-4388-468D-A174-97669AA8C3FF}

Но лучше их помещать в файл *.lic (простой текстовый файл в папке %programdata%\Crypto pro - ключи продукта записаны построчно).

@CryptoDed
Copy link
Author

Добавил функцию - которая по адресу функции в advapi.dll даёт ссылку на её имя из таблицы импорта экзешника.
Используется в обработчике эксцепшенов в примере.

@CryptoDed
Copy link
Author

формирование триальных ключей:

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}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment