commit 5b4f60d116fd4b1bfa02499d055c6b62e94cec42 Author: BitCookies Date: Sun Aug 9 16:48:33 2020 +0800 🔑 Release WinRAR Keygen Release WinRAR Keygen diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..e257ff9 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": "无配置" +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..ff13c35 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,7 @@ +{ + "ExpandedNodes": [ + "" + ], + "SelectedNode": "\\winrar-keygen.sln", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..67e5a01 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/.vs/winrar-keygen/v16/.suo b/.vs/winrar-keygen/v16/.suo new file mode 100644 index 0000000..cc44a54 Binary files /dev/null and b/.vs/winrar-keygen/v16/.suo differ diff --git a/.vs/winrar-keygen/v16/Browse.VC.db b/.vs/winrar-keygen/v16/Browse.VC.db new file mode 100644 index 0000000..4fbf427 Binary files /dev/null and b/.vs/winrar-keygen/v16/Browse.VC.db differ diff --git a/.vs/winrar-keygen/v16/ipch/AutoPCH/c0f0bdcf41a1ec98/_TMAIN.ipch b/.vs/winrar-keygen/v16/ipch/AutoPCH/c0f0bdcf41a1ec98/_TMAIN.ipch new file mode 100644 index 0000000..3ce0646 Binary files /dev/null and b/.vs/winrar-keygen/v16/ipch/AutoPCH/c0f0bdcf41a1ec98/_TMAIN.ipch differ diff --git a/BigInteger.hpp b/BigInteger.hpp new file mode 100644 index 0000000..11efac2 --- /dev/null +++ b/BigInteger.hpp @@ -0,0 +1,324 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +class BigInteger { +private: + mpz_t _Value; +public: + + BigInteger() noexcept { + mpz_init(_Value); + } + + template + BigInteger(__IntegerType SmallInteger) noexcept { + // __IntegerType must be a integer type, i.e. char, int, unsigned long... + static_assert(std::is_integral<__IntegerType>::value); + + if constexpr (std::is_signed<__IntegerType>::value) { + mpz_init_set_sx(_Value, SmallInteger); + } else { + mpz_init_set_ux(_Value, SmallInteger); + } + } + + BigInteger(bool IsNegative, const void* lpBuffer, size_t cbBuffer, bool UseLittleEndian) noexcept { + mpz_init(_Value); + mpz_import(_Value, cbBuffer, UseLittleEndian ? -1 : 1, sizeof(unsigned char), 0, 0, lpBuffer); + if (IsNegative) + mpz_neg(_Value, _Value); + } + + BigInteger(bool IsNegative, const std::vector& Buffer, bool UseLittleEndian) noexcept { + mpz_init(_Value); + mpz_import(_Value, Buffer.size(), UseLittleEndian ? -1 : 1, sizeof(unsigned char), 0, 0, Buffer.data()); + if (IsNegative) + mpz_neg(_Value, _Value); + } + + BigInteger(const char* lpszValue) noexcept { + mpz_init_set_str(_Value, lpszValue, 0); + } + + BigInteger(const std::string& szValue) noexcept { + mpz_init_set_str(_Value, szValue.c_str(), 0); + } + + BigInteger(const BigInteger& Other) noexcept { + mpz_init(_Value); + mpz_set(_Value, Other._Value); + } + + BigInteger(BigInteger&& Other) noexcept { + mpz_init(_Value); + mpz_swap(_Value, Other._Value); + } + + BigInteger& operator=(const BigInteger& Other) noexcept { + if (this != &Other) { + mpz_set(_Value, Other._Value); + } + return *this; + } + + BigInteger& operator=(BigInteger&& Other) noexcept { + if (this != &Other) { + mpz_swap(_Value, Other._Value); + mpz_clear(Other._Value); + } + return *this; + } + + template + BigInteger& operator=(__IntegerType SmallInteger) noexcept { + // __IntegerType must be a integer type, i.e. char, int, unsigned long... + static_assert(std::is_integral<__IntegerType>::value); + + if constexpr (std::is_signed<__IntegerType>::value) { + mpz_set_sx(_Value, SmallInteger); + } else { + mpz_set_ux(_Value, SmallInteger); + } + + return *this; + } + + BigInteger& operator=(const char* lpszValue) noexcept { + mpz_init_set_str(_Value, lpszValue, 0); + return *this; + } + + bool operator==(const BigInteger& Other) const noexcept { + return mpz_cmp(_Value, Other._Value) == 0; + } + + bool operator!=(const BigInteger& Other) const noexcept { + return mpz_cmp(_Value, Other._Value) != 0; + } + + bool operator<(const BigInteger& Other) const noexcept { + return mpz_cmp(_Value, Other._Value) < 0; + } + + bool operator<=(const BigInteger& Other) const noexcept { + auto d = mpz_cmp(_Value, Other._Value); + return d < 0 || d == 0; + } + + bool operator>(const BigInteger& Other) const noexcept { + return mpz_cmp(_Value, Other._Value) > 0; + } + + bool operator>=(const BigInteger& Other) const noexcept { + auto d = mpz_cmp(_Value, Other._Value); + return d > 0 || d == 0; + } + + BigInteger operator-() const noexcept { + BigInteger Result; + mpz_neg(Result._Value, _Value); + return Result; + } + + BigInteger operator+(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_add(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator+=(const BigInteger& Other) noexcept { + mpz_add(_Value, _Value, Other._Value); + return *this; + } + + BigInteger operator-(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_sub(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator-=(const BigInteger& Other) noexcept { + mpz_sub(_Value, _Value, Other._Value); + return *this; + } + + BigInteger operator*(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_mul(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator*=(const BigInteger& Other) noexcept { + mpz_mul(_Value, _Value, Other._Value); + return *this; + } + + BigInteger operator/(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_fdiv_q(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator/=(const BigInteger& Other) noexcept { + mpz_fdiv_q(_Value, _Value, Other._Value); + return *this; + } + + BigInteger operator%(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_fdiv_r(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator%=(const BigInteger& Other) noexcept { + mpz_fdiv_r(_Value, _Value, Other._Value); + return *this; + } + + BigInteger operator~() const noexcept { + BigInteger Result; + mpz_com(Result._Value, _Value); + return Result; + } + + BigInteger operator&(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_and(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator&=(const BigInteger& Other) noexcept { + mpz_and(_Value, _Value, Other._Value); + return *this; + } + + BigInteger operator|(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_ior(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator|=(const BigInteger& Other) noexcept { + mpz_ior(_Value, _Value, Other._Value); + return *this; + } + + BigInteger operator^(const BigInteger& Other) const noexcept { + BigInteger Result; + mpz_xor(Result._Value, _Value, Other._Value); + return Result; + } + + BigInteger& operator^=(const BigInteger& Other) noexcept { + mpz_xor(_Value, _Value, Other._Value); + return *this; + } + + BigInteger& operator++() noexcept { + mpz_add_ui(_Value, _Value, 1); + return *this; + } + + BigInteger operator++(int) noexcept { + BigInteger Result(*this); + mpz_add_ui(_Value, _Value, 1); + return Result; + } + + BigInteger& operator--() noexcept { + mpz_sub_ui(_Value, _Value, 1); + return *this; + } + + BigInteger operator--(int) noexcept { + BigInteger Result(*this); + mpz_sub_ui(_Value, _Value, 1); + return Result; + } + + bool IsZero() const noexcept { + return mpz_sgn(_Value) == 0; + } + + bool IsPositive() const noexcept { + return mpz_sgn(_Value) > 0; + } + + bool IsNegative() const noexcept { + return mpz_sgn(_Value) < 0; + } + + bool IsOne() const noexcept { + return mpz_cmp_si(_Value, 1) == 0; + } + + BigInteger& Load(bool IsNegative, const void* lpBuffer, size_t cbBuffer, bool UseLittleEndian) noexcept { + mpz_import(_Value, cbBuffer, UseLittleEndian ? -1 : 1, sizeof(uint8_t), 0, 0, lpBuffer); + if (IsNegative) + mpz_neg(_Value, _Value); + return *this; + } + + BigInteger& Load(bool IsNegative, const std::vector Buffer, bool UseLittleEndian) noexcept { + mpz_import(_Value, Buffer.size(), UseLittleEndian ? -1 : 1, sizeof(uint8_t), 0, 0, Buffer.data()); + if (IsNegative) + mpz_neg(_Value, _Value); + return *this; + } + + void DumpAbs(void* lpBuffer, size_t cbBuffer, bool UseLittleEndian) const { + size_t bit_size = mpz_sizeinbase(_Value, 2); + size_t storage_size = (bit_size + 7) / 8; + if (cbBuffer >= storage_size) { + size_t bytes_written; + mpz_export(lpBuffer, &bytes_written, UseLittleEndian ? -1 : 1, sizeof(uint8_t), 0, 0, _Value); + memset(reinterpret_cast(lpBuffer) + bytes_written, 0, cbBuffer - bytes_written); + } else { + throw std::length_error("Insufficient buffer."); + } + } + + std::vector DumpAbs(bool UseLittleEndian) const noexcept { + size_t bit_size = mpz_sizeinbase(_Value, 2); + size_t storage_size = (bit_size + 7) / 8; + std::vector bytes(storage_size); + mpz_export(bytes.data(), nullptr, UseLittleEndian ? -1 : 1, sizeof(uint8_t), 0, 0, _Value); + return bytes; + } + + size_t BitLength() const noexcept { + return mpz_sizeinbase(_Value, 2); + } + + bool TestBit(size_t i) const noexcept { + return mpz_tstbit(_Value, i) != 0; + } + + void SetBit(size_t i) noexcept { + mpz_setbit(_Value, i); + } + + std::string ToString(size_t Base, bool LowerCase) const { + if (2 <= Base && Base <= 10 + 26) { + int base = LowerCase ? static_cast(Base) : -static_cast(Base); + std::string s(mpz_sizeinbase(_Value, base) + 2, '\x00'); + + mpz_get_str(s.data(), base, _Value); + + while (s.back() == '\x00') { + s.pop_back(); + } + + return s; + } else { + throw std::invalid_argument("Invalid base value."); + } + } +}; + diff --git a/EllipticCurveGF2m.hpp b/EllipticCurveGF2m.hpp new file mode 100644 index 0000000..9542786 --- /dev/null +++ b/EllipticCurveGF2m.hpp @@ -0,0 +1,314 @@ +#pragma once +#include +#include +#include +#include +#include "BigInteger.hpp" + +template +class EllipticCurveGF2m { +private: + // y^2 + xy = x^3 + Ax^2 + B + + __FieldType _A; + __FieldType _B; + + void _VerifyParameters() const { + if (_B.IsZero()) { + throw std::invalid_argument("B cannot be zero."); + } + } +public: + + class Point { + friend EllipticCurveGF2m<__FieldType>; + private: + const EllipticCurveGF2m<__FieldType>& _Curve; + __FieldType _X; + __FieldType _Y; + + void _VerifyParameters() const { + auto Left = _Y.SquareValue() + _X * _Y; + auto Right = (_X + _Curve._A) * _X.SquareValue() + _Curve._B; + if (Left != Right) { + throw std::invalid_argument("New point is not on the curve specified."); + } + } + public: + + Point(const EllipticCurveGF2m<__FieldType>& Curve) noexcept : + _Curve(Curve) {} + + Point(const EllipticCurveGF2m<__FieldType>& Curve, const void* pbX, size_t cbX, const void* pbY, size_t cbY) : + _Curve(Curve), + _X(pbX, cbX), + _Y(pbY, cbY) + { + _VerifyParameters(); + } + + Point(const EllipticCurveGF2m<__FieldType>& Curve, const __FieldType& X, const __FieldType& Y) : + _Curve(Curve), _X(X), _Y(Y) + { + _VerifyParameters(); + } + + Point operator-() const noexcept { + return Point(_X, _X + _Y); + } + + Point& operator=(const Point& Other) { + if (&_Curve == &Other._Curve || _Curve == Other._Curve) { + _X = Other._X; + _Y = Other._Y; + return *this; + } else { + throw std::invalid_argument("Not on the same curve."); + } + } + + bool operator==(const Point& Other) const noexcept { + if (&_Curve == &Other._Curve || _Curve == Other._Curve) { + return _X == Other._X && _Y == Other._Y; + } else { + return false; + } + } + + bool operator!=(const Point& Other) const noexcept { + if (&_Curve == &Other._Curve || _Curve == Other._Curve) { + return _X != Other._X || _Y != Other._Y; + } else { + return true; + } + } + + const __FieldType& GetX() const noexcept { + return _X; + } + + const __FieldType& GetY() const noexcept { + return _Y; + } + + bool IsAtInfinity() const noexcept { + return _X.IsZero() && _Y.IsZero(); + } + + Point& Double() noexcept { + if (IsAtInfinity() == false) { + auto m = _Y / _X + _X; + + // NewX = m ^ 2 + m + a + __FieldType NewX = m.SquareValue(); + NewX += m; + NewX += _Curve._A; + + // NewY = X ^ 2 + (m + 1) * NewX + _Y = m.AddOne(); + _Y *= NewX; + _Y += _X.Square(); + + _X = NewX; + } + return *this; + } + + Point ValueOfDouble() const noexcept { + Point Result(_Curve); + + if (IsAtInfinity() == false) { + // m = X + Y / X + auto m = _Y / _X + _X; + + // NewX = m ^ 2 + m + a + Result._X = m.SquareValue(); + Result._X += m; + Result._X += _Curve._A; + + // NewY = X ^ 2 + (m + 1) * NewX + Result._Y = m.AddOne(); + Result._Y *= Result._X; + Result._Y += _X.SquareValue(); + } + + return Result; + } + + Point operator+(const Point& Other) const { + if (&_Curve == &Other._Curve || _Curve == Other._Curve) { + if (IsAtInfinity()) { + return Other; + } else { + if (this == &Other || _X == Other._X) { + return ValueOfDouble(); + } else { + Point Result(_Curve); + + // m = (Y0 + Y1) / (X0 + X1) + auto m = (_Y + Other._Y) / (_X + Other._X); + + // NewX = m ^ 2 + m + X0 + X1 + a + Result._X = m.SquareValue(); + Result._X += m; + Result._X += _X; + Result._X += Other._X; + Result._X += _Curve._A; + + // NewY = m * (X0 + NewX) + NewX + Y0 + Result._Y = _X + Result._X; + Result._Y *= m; + Result._Y += Result._X; + Result._Y += _Y; + + return Result; + } + } + } else { + throw std::invalid_argument("Not on the same curve."); + } + } + + Point& operator+=(const Point& Other) { + if (&_Curve == &Other._Curve || _Curve == Other._Curve) { + if (IsAtInfinity()) { + _X = Other._X; + _Y = Other._Y; + } else { + if (this == &Other || _X == Other._X) { + Double(); + } else { + Point Result(_Curve); + + // m = (Y0 + Y1) / (X0 + X1) + auto m = (_Y + Other._Y) / (_X + Other._X); + + // NewX = m ^ 2 + m + X0 + X1 + a + __FieldType NewX = m.SquareValue(); + NewX += m; + NewX += _X; + NewX += Other._X; + NewX += _Curve._A; + + // NewY = m * (X0 + NewX) + NewX + Y0 + _X += NewX; + _X *= m; + _X += NewX; + _Y += _X; + + _X = NewX; + } + } + return *this; + } else { + throw std::invalid_argument("Not on the same curve."); + } + } + + Point operator-(const Point& Other) const { + Point Result = -Other; + Result += *this; + return Result; + } + + Point& operator-=(const Point& Other) { + return *this += -Other; + } + + Point operator*(const BigInteger N) const noexcept { + Point Result(_Curve); + Point temp(*this); + size_t bit_length = N.BitLength(); + + for (size_t i = 0; i < bit_length; ++i) { + if (N.TestBit(i) == true) + Result += temp; + temp.Double(); + } + + return Result; + } + + Point operator*=(const BigInteger N) noexcept { + Point Result(_Curve); + size_t bit_length = N.BitLength(); + + for (size_t i = 0; i < bit_length; ++i) { + if (N.TestBit(i) == true) + Result += *this; + Double(); + } + + *this = Result; + } + + // SEC 1: Elliptic Curve Cryptography + // 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion + std::vector Dump() const noexcept { + if (IsAtInfinity()) { + std::vector bytes = { 0x00 }; + return bytes; + } else { + std::vector bytes = { 0x04 }; + std::vector xbytes = _X.Dump(); + std::vector ybytes = _Y.Dump(); + std::reverse(xbytes.begin(), xbytes.end()); // to big endian + std::reverse(ybytes.begin(), ybytes.end()); // to big endian + bytes.insert(bytes.end(), xbytes.begin(), xbytes.end()); + bytes.insert(bytes.end(), ybytes.begin(), ybytes.end()); + return bytes; + } + } + + // SEC 1: Elliptic Curve Cryptography + // 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion + std::vector DumpCompressed() const noexcept { + if (IsAtInfinity()) { + std::vector bytes = { 0x00 }; + return bytes; + } else { + std::vector bytes(1); + std::vector xbytes = _X.Dump(); + std::vector zbytes = (_Y / _X).Dump(); + + if (zbytes[0] & 1) { + bytes[0] = 0x03; + } else { + bytes[0] = 0x02; + } + + std::reverse(xbytes.begin(), xbytes.end()); // to big endian + bytes.insert(bytes.end(), xbytes.begin(), xbytes.end()); + return bytes; + } + } + }; + + EllipticCurveGF2m(const __FieldType& A, const __FieldType& B) : _A(A), _B(B) { + _VerifyParameters(); + } + + EllipticCurveGF2m(const void* pbA, size_t cbA, const void* pbB, size_t cbB) : _A(pbA, cbA), _B(pbB, cbB) { + _VerifyParameters(); + } + + bool operator==(const EllipticCurveGF2m<__FieldType>& Other) const noexcept { + return _A == Other._A && _B == Other._B; + } + + bool operator!=(const EllipticCurveGF2m<__FieldType>& Other) const noexcept { + return _A != Other._A || _B != Other._B; + } + + Point GetInfinityPoint() const noexcept { + return Point(*this); + } + + Point GetPoint(const __FieldType& X, const __FieldType& Y) const { + return Point(*this, X, Y); + } + + Point GetPoint(const void* pbX, size_t cbX, const void* pbY, size_t cbY) const { + return Point(*this, pbX, cbX, pbY, cbY); + } +}; diff --git a/GaloisField.hpp b/GaloisField.hpp new file mode 100644 index 0000000..ac6a450 --- /dev/null +++ b/GaloisField.hpp @@ -0,0 +1,226 @@ +#pragma once +#include +#include +#include +#include + +struct GaloisFieldInitByZero {}; +struct GaloisFieldInitByOne {}; +struct GaloisFieldInitByElement {}; +struct GaloisFieldInitByDump {}; + +template +class GaloisField { +public: + static constexpr size_t BitSizeValue = __FieldTraits::BitSizeValue; + static constexpr size_t DumpSizeValue = __FieldTraits::DumpSizeValue; +private: + static_assert(std::is_pod::value == true); + + typename __FieldTraits::ElementType _Val; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 26495) // disable uninitialized warning +#endif + struct NoInitialization {}; + GaloisField(NoInitialization) noexcept {}; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +public: + GaloisField() noexcept { + __FieldTraits::SetZero(_Val); + } + + GaloisField(GaloisFieldInitByZero) noexcept { + __FieldTraits::SetZero(_Val); + } + + GaloisField(GaloisFieldInitByOne) noexcept { + __FieldTraits::SetOne(_Val); + } + + GaloisField(GaloisFieldInitByElement, const typename __FieldTraits::ElementType& Element) { + __FieldTraits::Verify(Element); + _Val = Element; + } + + GaloisField(GaloisFieldInitByDump, const void* pbBuffer, size_t cbBuffer) { + __FieldTraits::Load(_Val, pbBuffer, cbBuffer); + } + + template::type> + GaloisField(GaloisFieldInitByDump, uintptr_t SerializedValue) { + __FieldTraits::Load(_Val, SerializedValue); + } + + GaloisField<__FieldTraits>& operator=(const typename __FieldTraits::ElementType& Element) { + __FieldTraits::Verify(Element); + _Val = Element; + return *this; + } + + template::type> + GaloisField<__FieldTraits>& operator=(uintptr_t SerializedValue) { + __FieldTraits::Load(_Val, SerializedValue); + return *this; + } + + bool IsZero() const noexcept { + return __FieldTraits::IsZero(_Val); + } + + bool IsOne() const noexcept { + return __FieldTraits::IsOne(_Val); + } + + bool operator==(const GaloisField<__FieldTraits>& Other) const noexcept { + return __FieldTraits::IsEqual(_Val, Other._Val); + } + + bool operator!=(const GaloisField<__FieldTraits>& Other) const noexcept { + return __FieldTraits::IsEqual(_Val, Other._Val) == false; + } + + GaloisField<__FieldTraits> operator+(const GaloisField<__FieldTraits>& Other) const noexcept { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::Add(Result._Val, _Val, Other._Val); + return Result; + } + + GaloisField<__FieldTraits>& operator+=(const GaloisField<__FieldTraits>& Other) noexcept { + __FieldTraits::AddAssign(_Val, Other._Val); + return *this; + } + + GaloisField<__FieldTraits> operator-(const GaloisField<__FieldTraits>& Other) const noexcept { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::Substract(Result._Val, _Val, Other._Val); + return Result; + } + + GaloisField<__FieldTraits>& operator-=(const GaloisField<__FieldTraits>& Other) noexcept { + __FieldTraits::SubstractAssign(_Val, Other._Val); + return *this; + } + + GaloisField<__FieldTraits> operator*(const GaloisField<__FieldTraits>& Other) const noexcept { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::Multiply(Result._Val, _Val, Other._Val); + return Result; + } + + GaloisField<__FieldTraits>& operator*=(const GaloisField<__FieldTraits>& Other) noexcept { + __FieldTraits::MultiplyAssign(_Val, Other._Val); + return *this; + } + + GaloisField<__FieldTraits> operator/(const GaloisField<__FieldTraits>& Other) const { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::Divide(Result._Val, _Val, Other._Val); + return Result; + } + + GaloisField<__FieldTraits>& operator/=(const GaloisField<__FieldTraits>& Other) { + __FieldTraits::DivideAssign(_Val, Other._Val); + return *this; + } + + GaloisField<__FieldTraits>& operator++() noexcept { // prefix ++ + __FieldTraits::AddOneAssign(_Val); + return *this; + } + + GaloisField<__FieldTraits> operator++(int) noexcept { // postfix ++ + GaloisField<__FieldTraits> Prev(*this); + __FieldTraits::AddOneAssign(_Val); + return Prev; + } + + GaloisField<__FieldTraits>& operator--() noexcept { // prefix -- + __FieldTraits::SubstractOneAssign(_Val); + return *this; + } + + GaloisField<__FieldTraits> operator--(int) noexcept { // postfix -- + GaloisField<__FieldTraits> Prev(*this); + __FieldTraits::SubstractOneAssign(_Val); + return Prev; + } + + GaloisField<__FieldTraits>& Inverse() { + __FieldTraits::InverseAssign(_Val); + return *this; + } + + GaloisField<__FieldTraits> InverseValue() const { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::Inverse(Result, _Val); + return Result; + } + + GaloisField<__FieldTraits>& AddOne() noexcept { + __FieldTraits::AddOneAssign(_Val); + return *this; + } + + GaloisField<__FieldTraits> AddOneValue() const noexcept { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::AddOne(Result._Val, _Val); + return Result; + } + + GaloisField<__FieldTraits>& SubstractOne() noexcept { + __FieldTraits::SubstractOneAssign(_Val); + return *this; + } + + GaloisField<__FieldTraits> SubstractOneValue() const noexcept { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::SubstractOne(Result._Val, _Val); + return Result; + } + + GaloisField<__FieldTraits>& Square() noexcept { + __FieldTraits::SquareAssign(_Val); + return *this; + } + + GaloisField<__FieldTraits> SquareValue() const noexcept { + GaloisField<__FieldTraits> Result(NoInitialization{}); + __FieldTraits::Square(Result._Val, _Val); + return Result; + } + + template::type> + uintptr_t Dump() const noexcept { + return __FieldTraits::Dump(_Val); + } + + size_t Dump(void* lpBuffer, size_t cbBuffer) const { + return __FieldTraits::Dump(_Val, lpBuffer, cbBuffer); + } + + std::vector Dump() const noexcept { + return __FieldTraits::Dump(_Val); + } + + template::type> + GaloisField<__FieldTraits>& Load(uintptr_t SerializedValue) { + __FieldTraits::Load(_Val, SerializedValue); + return *this; + } + + GaloisField<__FieldTraits>& Load(const void* lpBuffer, size_t cbBuffer) { + __FieldTraits::Load(_Val, lpBuffer, cbBuffer); + return *this; + } + + GaloisField<__FieldTraits>& Load(const std::vector& Buffer) { + __FieldTraits::Load(_Val, Buffer); + return *this; + } +}; + diff --git a/Hasher.hpp b/Hasher.hpp new file mode 100644 index 0000000..136de65 --- /dev/null +++ b/Hasher.hpp @@ -0,0 +1,62 @@ +#pragma once +#include + +template +class Hasher { +public: + static constexpr size_t BlockSizeValue = __HashTraits::BlockSize; + static constexpr size_t DigestSizeValue = __HashTraits::DigestSize; + using DigestType = typename __HashTraits::DigestType; +private: + using ContextType = typename __HashTraits::ContextType; + ContextType _Ctx; +public: + + Hasher(__HashTraits) : + _Ctx(__HashTraits::ContextCreate()) {} + + template + Hasher(__HashTraits, __Ts&&... Args) : + _Ctx(__HashTraits::ContextCreate(std::forward<__Ts>(Args)...)) {} + + Hasher(const Hasher<__HashTraits>& Other) : + _Ctx(__HashTraits::ContextCopy(Other._Ctx)) {} + + Hasher(Hasher<__HashTraits>&& Other) noexcept : + _Ctx(std::move(Other._Ctx)) {} + + Hasher<__HashTraits>& operator=(const Hasher<__HashTraits>& Other) { + ContextType t = __HashTraits::ContextCopy(Other._Ctx); + __HashTraits::ContextDestroy(_Ctx); + _Ctx = std::move(t); + return *this; + } + + Hasher<__HashTraits>& operator=(Hasher<__HashTraits>&& Other) noexcept { + _Ctx = std::move(Other._Ctx); + return *this; + } + + constexpr size_t BlockSize() const noexcept { + return BlockSizeValue; + } + + constexpr size_t DigestSize() const noexcept { + return DigestSizeValue; + } + + void Update(const void* lpBuffer, size_t cbBuffer) noexcept { + __HashTraits::ContextUpdate(_Ctx, lpBuffer, cbBuffer); + } + + DigestType Evaluate() const noexcept { + DigestType Digest; + __HashTraits::ContextEvaluate(_Ctx, Digest); + return Digest; + } + + ~Hasher() { + __HashTraits::ContextDestroy(_Ctx); + } +}; + diff --git a/HasherCrc32Traits.hpp b/HasherCrc32Traits.hpp new file mode 100644 index 0000000..cd9e31c --- /dev/null +++ b/HasherCrc32Traits.hpp @@ -0,0 +1,198 @@ +#pragma once +#include +#include + +template +struct HasherCrc32Traits { + static constexpr size_t BlockSize = 0; + static constexpr size_t DigestSize = 32 / 8; + + using DigestType = uint32_t; + using LookupTableType = uint32_t[256]; + + struct ContextType { + uint32_t Value; + + ContextType() noexcept : + Value(0) {} + + ContextType(uint32_t InitialValue) noexcept : + Value(InitialValue) {} + + ContextType(const ContextType& Other) noexcept = default; + + ContextType(ContextType&& Other) noexcept : Value(Other.Value) { + Other.Value = 0; + } + + ContextType& operator=(const ContextType& Other) noexcept = default; + + ContextType& operator=(ContextType&& Other) noexcept { + Value = Other.Value; + Other.Value = 0; + return *this; + } + }; + + static const LookupTableType& InitializeLookupTable() noexcept { + static LookupTableType LookupTable = {}; + + if (LookupTable[1] == 0) { + for (unsigned i = 0; i < 256; ++i) { + uint32_t result = i; + for (unsigned j = 0; j < 8; ++j) { + if (result % 2) { + result /= 2; + result ^= __Polynomial; + } else { + result /= 2; + } + } + LookupTable[i] = result; + } + } + + return LookupTable; + } + + static inline const LookupTableType& LookupTable = InitializeLookupTable(); + + static inline ContextType ContextCreate() noexcept { + ContextType Ctx; + return Ctx; + } + + static inline ContextType ContextCreate(const void* lpBuffer, size_t cbBuffer) noexcept { + ContextType Ctx; + ContextUpdate(Ctx, lpBuffer, cbBuffer); + return Ctx; + } + + static inline ContextType ContextCreate(uint32_t InitialValue) noexcept { + ContextType Ctx(InitialValue); + return Ctx; + } + + static inline ContextType ContextCreate(uint32_t InitialValue, const void* lpBuffer, size_t cbBuffer) noexcept { + ContextType Ctx; + ContextUpdate(Ctx, lpBuffer, cbBuffer); + return Ctx; + } + + static inline ContextType ContextCopy(const ContextType& Ctx) noexcept { + return Ctx; + } + + static inline void ContextUpdate(ContextType& Ctx, const void* lpBuffer, size_t cbBuffer) noexcept { + auto pbBuffer = reinterpret_cast(lpBuffer); + Ctx.Value = ~Ctx.Value; + for (size_t i = 0; i < cbBuffer; ++i) { + Ctx.Value = (Ctx.Value >> 8) ^ LookupTable[static_cast(Ctx.Value) ^ pbBuffer[i]]; + } + Ctx.Value = ~Ctx.Value; + } + + static inline void ContextEvaluate(const ContextType& Ctx, DigestType& Digest) noexcept { + Digest = Ctx.Value; + } + + static inline void ContextDestroy(ContextType& Ctx) noexcept { + Ctx.Value = 0; + } +}; + +#ifdef _MSC_VER +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma comment(lib, "ntdll") + + // available on WindowsXP and above + NTSYSAPI + DWORD + NTAPI + RtlComputeCrc32( + _In_ DWORD InitialCrc, + _In_reads_bytes_(Size) const void* Buffer, + _In_ size_t Size + ); + +#ifdef __cplusplus +} +#endif + +template<> +struct HasherCrc32Traits<0xEDB88320> { + static constexpr size_t BlockSize = 0; + static constexpr size_t DigestSize = 32 / 8; + + using DigestType = uint32_t; + + struct ContextType { + uint32_t Value; + + ContextType() noexcept : + Value(0) {} + + ContextType(uint32_t InitialValue) noexcept : + Value(InitialValue) {} + + ContextType(const ContextType& Other) noexcept = default; + + ContextType(ContextType&& Other) noexcept : Value(Other.Value) { + Other.Value = 0; + } + + ContextType& operator=(const ContextType& Other) noexcept = default; + + ContextType& operator=(ContextType&& Other) noexcept { + Value = Other.Value; + Other.Value = 0; + return *this; + } + }; + + static inline ContextType ContextCreate() noexcept { + ContextType Ctx; + return Ctx; + } + + static inline ContextType ContextCreate(const void* lpBuffer, size_t cbBuffer) noexcept { + ContextType Ctx; + ContextUpdate(Ctx, lpBuffer, cbBuffer); + return Ctx; + } + + static inline ContextType ContextCreate(uint32_t InitialValue) noexcept { + ContextType Ctx(InitialValue); + return Ctx; + } + + static inline ContextType ContextCreate(uint32_t InitialValue, const void* lpBuffer, size_t cbBuffer) noexcept { + ContextType Ctx; + ContextUpdate(Ctx, lpBuffer, cbBuffer); + return Ctx; + } + + static inline ContextType ContextCopy(const ContextType& Ctx) noexcept { + return Ctx; + } + + static inline void ContextUpdate(ContextType& Ctx, const void* lpBuffer, size_t cbBuffer) noexcept { + Ctx.Value = RtlComputeCrc32(Ctx.Value, lpBuffer, cbBuffer); + } + + static inline void ContextEvaluate(const ContextType& Ctx, DigestType& Digest) noexcept { + Digest = Ctx.Value; + } + + static inline void ContextDestroy(ContextType& Ctx) noexcept { + Ctx.Value = 0; + } +}; + +#endif // #ifdef _MSC_VER + diff --git a/HasherSha1Traits.hpp b/HasherSha1Traits.hpp new file mode 100644 index 0000000..2c2aead --- /dev/null +++ b/HasherSha1Traits.hpp @@ -0,0 +1,153 @@ +#pragma once + +#ifdef _MSC_VER +#include +#include +#include + +struct HasherSha1Traits { +public: + static constexpr size_t BlockSize = 512 / 8; + static constexpr size_t DigestSize = 160 / 8; + + struct DigestType { + BYTE Bytes[DigestSize]; + }; + + struct ContextType { + HCRYPTHASH hHash; + + ContextType() noexcept : + hHash(NULL) {} + + ContextType(HCRYPTHASH HashHandle) noexcept : + hHash(HashHandle) {} + + ContextType(const ContextType& Other) noexcept = default; + + ContextType(ContextType&& Other) noexcept : hHash(Other.hHash) { + Other.hHash = NULL; + } + + ContextType& operator=(const ContextType& Other) noexcept = default; + + ContextType& operator=(ContextType&& Other) noexcept { + hHash = Other.hHash; + Other.hHash = NULL; + return *this; + } + }; + +private: + + static inline struct ContextProvider { + HCRYPTPROV Handle; + + ~ContextProvider() { + if (Handle) { + CryptReleaseContext(Handle, 0); + Handle = NULL; + } + } + } CryptProvider; + +public: + static inline ContextType ContextCreate() { + ContextType Ctx; + + if (CryptProvider.Handle == NULL) { + if (!CryptAcquireContext(&CryptProvider.Handle, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0)) { + auto err = GetLastError(); + if (err == NTE_BAD_KEYSET) { + if (!CryptAcquireContext(&CryptProvider.Handle, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET)) { + err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + } else { + throw std::system_error(err, std::system_category()); + } + } + } + + if (!CryptCreateHash(CryptProvider.Handle, CALG_SHA1, NULL, 0, &Ctx.hHash)) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + + return Ctx; + } + + static inline ContextType ContextCreate(const void* lpBuffer, size_t cbBuffer) { + ContextType Ctx; + + if (CryptProvider.Handle == NULL) { + if (!CryptAcquireContext(&CryptProvider.Handle, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0)) { + auto err = GetLastError(); + if (err == NTE_BAD_KEYSET) { + if (!CryptAcquireContext(&CryptProvider.Handle, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET)) { + err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + } else { + throw std::system_error(err, std::system_category()); + } + } + } + + if (!CryptCreateHash(CryptProvider.Handle, CALG_SHA1, NULL, 0, &Ctx.hHash)) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + + ContextUpdate(Ctx, lpBuffer, cbBuffer); + + return Ctx; + } + + static inline ContextType ContextCopy(const ContextType& Ctx) { + ContextType NewCtx; + if (!CryptDuplicateHash(Ctx.hHash, NULL, 0, &NewCtx.hHash)) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + return NewCtx; + } + + static inline void ContextUpdate(ContextType& Ctx, const void* lpBuffer, size_t cbBuffer) { + if constexpr (sizeof(size_t) <= sizeof(DWORD)) { + if (!CryptHashData(Ctx.hHash, reinterpret_cast(lpBuffer), static_cast(cbBuffer), 0)) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + } else { + size_t BytesRead = 0; + DWORD BytesToRead = cbBuffer - BytesRead > MAXDWORD ? MAXDWORD : static_cast(cbBuffer - BytesRead); + + do { + if (!CryptHashData(Ctx.hHash, reinterpret_cast(lpBuffer) + BytesRead, BytesToRead, 0)) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + BytesRead += BytesToRead; + BytesToRead = cbBuffer - BytesRead > MAXDWORD ? MAXDWORD : static_cast(cbBuffer - BytesRead); + } while (BytesToRead); + } + } + + static inline void ContextEvaluate(const ContextType& Ctx, DigestType& Digest) { + DWORD SizeOfDigest = sizeof(Digest.Bytes); + if (!CryptGetHashParam(Ctx.hHash, HP_HASHVAL, Digest.Bytes, &SizeOfDigest, 0)) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + } + + static inline void ContextDestroy(ContextType& Ctx) noexcept { + if (Ctx.hHash) { + CryptDestroyHash(Ctx.hHash); + Ctx.hHash = NULL; + } + } +}; +#endif + diff --git a/README.HOW_DOES_IT_WORK.md b/README.HOW_DOES_IT_WORK.md new file mode 100644 index 0000000..59ec4a0 --- /dev/null +++ b/README.HOW_DOES_IT_WORK.md @@ -0,0 +1,321 @@ +[GF2-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20%5Ctextrm%7BGF%7D%282%29 +[GF2p15-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20%5Ctextrm%7BGF%7D%282%5E%7B15%7D%29 +[GF2p15p17-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29 +[A-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20A +[B-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20B +[D-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20D +[G-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20G +[M-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20M +[P-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20P +[h-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20h +[k-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20k +[l-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20l +[n-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20n +[r-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20r +[s-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20s +[T-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20T +[UU-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20U +[LL-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20L +[Rnd-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Rnd +[Temp-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Temp +[UID-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20UID +[Data-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data +[Data0-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E0 +[Data1-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E1 +[Data2-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E2 +[Data3-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E3 + +# How is "rarreg.key" generated? + +WinRAR uses an ECC-based signature algorithm to generate `rarreg.key`. The algorithm it used is a varient of Chinese SM2 digital signature algorithm. Different to many standard ECDSAs, the curve that WinRAR selected is a curve over composite field ![GF2p15p17-inlined]. + +## 1. Composite field ![GF2p15p17-inlined] + +Elements in ground field ![GF2p15-inlined] are represented with standard basis, i.e. polynomial basis. The irreducible polynomial is + +

+ + +where each coefficients is in ![GF2-inlined]. If we use + +

+ + +as the standard basis of the ground field, an element ![A-inlined] in ![GF2p15-inlined] can be denoted as + +

+ + +--- + +The irreducible polynomial of composite field ![GF2p15p17-inlined] is + +

+ + +where each coefficients is in ![GF2p15-inlined]. If we use + +

+ + +as the standard basis of the composite field, an element ![B-inlined] in ![GF2p15p17-inlined] can be denoted as + +

+ + +--- + +For clarity, we use ![D-inlined], which is a 255-bits-long integer to denote an element ![B-inlined] in ![GF2p15p17-inlined]. The map between them is + +

+ + +## 2. Elliptic curve over ![GF2p15p17-inlined] + +The equation of the elliptic curve that WinRAR uses is + +

+ + +The base point ![G-inlined] is + +

+ + +whose order ![n-inlined] is + +

+ + +## 3. Message hash algorithm + +We use + +

+ + +to denote a message whose length is ![l-inlined]. So the SHA1 value of ![M-inlined] should be + +

+ + +where ![](http://latex.codecogs.com/svg.latex?%5Cinline%20S_0%2CS_1%2CS_2%2CS_3%2CS_4) are 5 state values when SHA1 outputs. Generally speaking, the final SHA1 value should be the join of these 5 state values while each of state values is serialized in big-endian. + +However, WinRAR doesn't serialize the 5 state values. Instead, it use a big integer ![h-inlined] as the hash of the input message. + +

+ + +## 4. ECC digital signature algorithm + +We use ![k-inlined] to denote private key, ![P-inlined] to denote public key. So there must be + +

+ + +If we use ![h-inlined] to denote the hash of input data, WinRAR use the following algorithm to perform signing: + +1. Generate a random big integer ![Rnd-inlined] which satisfies ![](http://latex.codecogs.com/svg.latex?%5Cinline%200%3CRnd%3Cn). + +2. Calculate ![r-inlined] + +

+ +

+ + where ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28Rnd%20%5Ccdot%20G%29_x) means we take X coordinate of ![](http://latex.codecogs.com/svg.latex?%5Cinline%20Rnd%20%5Ccdot%20G) and convert it from ![GF2p15p17-inlined] to a big integer. + + If ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r%3D0) or ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r+Rnd%3Dn), go back to step 1. + +3. Calculate ![s-inlined] + +

+ +

+ + If ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s%3D0), go back to step 1. + +4. Output ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28r%2Cs%29). + +## 5. WinRAR private key generation algorithm + +We use + +

+ +

+ +to denote input data whose length is ![l-inlined]. WinRAR use it to generate private key ![k-inlined]. + +1. We use ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_0%2Cg_1%2Cg_2%2Cg_3%2Cg_4%2Cg_5) to denote 6 32-bits-long integer. So there is + +

+ +

+ +2. Let ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_0%3D0). + +3. If ![](http://latex.codecogs.com/svg.latex?%5Cinline%20l%5Cneq%200), we calculate SHA1 value of ![T-inlined]. Then assign SHA1 state value ![](http://latex.codecogs.com/svg.latex?%5Cinline%20S_i) to ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_%7Bi+1%7D): + +

+ +

+ + Otherwise, when ![](http://latex.codecogs.com/svg.latex?%5Cinline%20l%3D0), we let + +

+ +

+ +4. Regard ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_0) as counter, add itself by 1. + + Calculate SHA1: + +

+ +

+ + We takes the lowest 16 bits of ![](http://latex.codecogs.com/svg.latex?%5Cinline%20S_0) and donote it as ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_%7Bg_0%7D). + +5. Repeat step 4 again with 14 times. + +6. After that, we will get ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_1%2Ck_2%2Ck_3%2C%5Cldots%2Ck_%7B15%7D). Then output private key + +

+ +

+ +## 6. The private key and public key of WinRAR + +Private key ![k-inlined] is + +

+ +

+ +This private key is generated by the algorithm describled in section 5 where the length of data ![T-inlined] is zero. + +Public key ![P-inlined] is + +

+ +

+ +## 7. Generation of "rarreg.key" + +The generation of license file `rarreg.key` requires 2 arguments: + +1. Username, an ANSI-encoded string, without null-terminator. Denoted as + +

+ +

+ +2. License type, an ANSI-encoded string, without null-terminator. Denoted as + +

+ +

+ +The following is the algorithm to generate `rarreg.key`. + +1. Use the algorithm describled in section 5, with argument ![UU-inlined], to generate private key ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_U) and public key ![](http://latex.codecogs.com/svg.latex?%5Cinline%20P_U). Then output hexlified public key string with SM2 compressed public key format. The hexlified public key is denoted as ![Temp-inlined]. + + The length of ![Temp-inlined] should be 64. If less, pad with `'0'` until the length is 64. + +2. Let ![Data3-inlined] be + +

+ +

+ +3. Use the algorithm describled in section 5, with argument ![Data3-inlined], to generate private key ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_%7BData%5E3%7D) and public key ![](http://latex.codecogs.com/svg.latex?%5Cinline%20P_%7BData%5E3%7D). Then output hexlified public key string with SM2 compressed public key format. The hexlified public key is denoted as ![Data0-inlined]. + + The length of ![Data0-inlined] should be 64. If less, pad with `'0'` until the length is 64. + +4. Let ![UID-inlined] be + +

+ +

+ +5. Use the algorithm describled in section 4, with argument ![LL-inlined] and private key ![k-inlined] describled section 6, to get signature ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28r_L%2Cs_L%29). + + The bit length of ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_L) and ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_L) shall not be more than 240. Otherwise, repeat this step. + +6. Convert ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_L) and ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_L) to hex-integer string ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Br_L%7D) and ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bs_L%7D), without `"0x"` prefix. + + If the length of ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Br_L%7D) or ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bs_L%7D) is less than 60, pad character `'0'` until the length is 60. + +7. Let ![Data1-inlined] be + +

+ +

+ +8. Let ![Temp-inlined] be + +

+ +

+ + Use the algorithm describled in section 4, with argument ![Temp-inlined] and private key ![k-inlined] describled section 6, to get signature ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28r_%7BTemp%7D%2Cs_%7BTemp%7D%29). + + The bit length of ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_%7BTemp%7D) and ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_%7BTemp%7D) shall not be more than 240. Otherwise, repeat this step. + +9. Convert ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_%7BTemp%7D) and ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_%7BTemp%7D) to hex-integer string ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Br_%7BTemp%7D%7D) and ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bs_%7BTemp%7D%7D), without `"0x"` prefix. + + If the length of ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Br_%7BTemp%7D%7D) or ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bs_%7BTemp%7D%7D) is less than 60, pad character `'0'` until the length is 60. + +10. Let ![Data2-inlined] be + +

+ +

+ +11. Calculate CRC32 value of + +

+ +

+ + The final checksum the complement of CRC32 value. + + Then convert the checksum to decimal string ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bchecksum%7D). If the length is less than 10, pad character `'0'` until the length is 10. + +12. Let ![Data-inlined] be + +

+ +

+ +13. Output with format + + * A fixed header `"RAR registration data"`, taking one line. + + * Username, taking one line. + + * License type, taking one line + + * UID, taking one line, with format: + +

+ +

+ + * Output ![Data-inlined], with 54 characters a line. + diff --git a/README.HOW_DOES_IT_WORK.zh-CN.md b/README.HOW_DOES_IT_WORK.zh-CN.md new file mode 100644 index 0000000..d51495f --- /dev/null +++ b/README.HOW_DOES_IT_WORK.zh-CN.md @@ -0,0 +1,320 @@ +[GF2-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20%5Ctextrm%7BGF%7D%282%29 +[GF2p15-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20%5Ctextrm%7BGF%7D%282%5E%7B15%7D%29 +[GF2p15p17-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29 +[A-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20A +[B-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20B +[D-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20D +[G-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20G +[M-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20M +[P-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20P +[h-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20h +[k-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20k +[l-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20l +[n-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20n +[r-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20r +[s-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20s +[T-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20T +[UU-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20U +[LL-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20L +[Rnd-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Rnd +[Temp-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Temp +[UID-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20UID +[Data-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data +[Data0-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E0 +[Data1-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E1 +[Data2-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E2 +[Data3-inlined]: http://latex.codecogs.com/svg.latex?%5Cinline%20Data%5E3 + +# "rarreg.key"是如何生成的? + +WinRAR使用了基于ECC的签名算法来生成 `rarreg.key` 文件,其使用的签名算法是中国SM2数字签名算法的变体。与各种标准ECDSA不同的是,WinRAR使用的椭圆曲线是一个基于复合域 ![GF2p15p17-inlined] 上的曲线。 + +## 1. 复合域 ![GF2p15p17-inlined] + +基域 ![GF2p15-inlined] 采用标准基(多项式基)来表达,采用的不可约多项式为: + +

+ + +各项系数全部位于 ![GF2-inlined]。设基域的标准基为: + +

+ + +则位于基域 ![GF2p15-inlined] 上的元素 ![A-inlined] 可以用如下方式表达: + +

+ + +--- + +复合域 ![GF2p15p17-inlined] 的不可约多项式为: + +

+ + +各项系数全部位于 ![GF2p15-inlined]。设复合域的标准基为: + +

+ + +则位于复合域 ![GF2p15p17-inlined] 上的元素 ![B-inlined] 可以用如下方式表达: + +

+ + +--- + +为了方便表述我们用255比特的大数 ![D-inlined] 来表示位于复合域 ![GF2p15p17-inlined] 上的元素 ![B-inlined]。它们的对应关系为: + +

+ + +## 2. 复合域 ![GF2p15p17-inlined] 上的椭圆曲线 + +曲线方程为: + +

+ + +基点 ![G-inlined] 为: + +

+ + +基点 ![G-inlined] 的阶 ![n-inlined] 为: + +

+ + +## 3. 消息哈希算法 + +设长度为 ![l-inlined] 的消息为: + +

+ + +则消息 ![M-inlined] 的SHA1值为: + +

+ + +其中 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20S_0%2CS_1%2CS_2%2CS_3%2CS_4) 为SHA1算法输出时的5个状态值;将这5个状态值按照大端字节序依次输出,即为的SHA1哈希值 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%5Ctextrm%7BSHA%7D_1%28M%29)。 + +WinRAR在做完SHA1计算后,采用大数 ![h-inlined] 作为ECC签名时消息的哈希: + +

+ + + +## 4. ECC签名算法 + +设私钥为 ![k-inlined],公钥为 ![P-inlined],即: + +

+ + +消息哈希为 ![h-inlined],则签名 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28r%2Cs%29) 为: + +1. 生成随机数 ![Rnd-inlined],满足 ![](http://latex.codecogs.com/svg.latex?%5Cinline%200%3CRnd%3Cn)。 + +2. 计算 ![r-inlined] + +

+ +

+ + 其中 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28Rnd%20%5Ccdot%20G%29_x) 表示取 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20Rnd%20%5Ccdot%20G) 的X坐标,同时将X坐标从 ![GF2p15p17-inlined] 转换为大数。 + + 若 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r%3D0) 或者 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r+Rnd%3Dn) 则回到步骤1。 + +3. 计算 ![s-inlined] + +

+ +

+ + 若 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s%3D0) 则回到步骤1。 + +4. 输出 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28r%2Cs%29)。 + +## 5. WinRAR的私钥生成算法 + +该算法会利用长度为 ![l-inlined] 的数据 + +

+ +

+ +来生成私钥 ![k-inlined]。 + +1. 设6个32位整数为 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_0%2Cg_1%2Cg_2%2Cg_3%2Cg_4%2Cg_5),则有 + +

+ +

+ +2. 令 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_0%3D0)。 + +3. 如果 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20l%5Cneq%200) 则计算 ![T-inlined] 的SHA1值,并将状态值 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20S_i) 赋值给 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_%7Bi+1%7D): + +

+ +

+ + 否则,即 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20l%3D0) 时,令: + +

+ +

+ +4. 把 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20g_0) 作为计数器,自增1。 + + 计算SHA1值: + +

+ +

+ + 取 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20S_0) 的低16位并记为 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_%7Bg_0%7D)。 + +5. 步骤4再重复14次。 + +6. 重复执行完后会得到 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_1%2Ck_2%2Ck_3%2C%5Cldots%2Ck_%7B15%7D),则输出私钥 + +

+ +

+ +## 6. WinRAR的公钥和私钥 + +WinRAR的私钥 ![k-inlined] 为: + +

+ +

+ +该私钥是通过算法5生成的,其中数据 ![T-inlined] 的长度为0。 + +公钥 ![P-inlined] 为: + +

+ +

+ +## 7. 授权文件"rarreg.key"的生成 + +授权文件的生成需要两个参数: + +1. 用户名的ANSI字符串,不包括null-terminator;记为 + +

+ +

+ +2. 授权类型的ANSI字符串,不包括null-terminator;记为 + +

+ +

+ +`rarreg.key` 的生成算法如下: + +1. 使用用户名 ![UU-inlined] 通过算法5计算出私钥 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_U) 以及公钥 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20P_U),并将公钥 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20P_U) 按照SM2压缩公钥格式以Hex字符串(ASCII编码)的形式输出。得到的Hex字符串记为临时值 ![Temp-inlined]。 + + ![Temp-inlined] 的长度应该为64;若长度不足,则在前面补字符`'0'`,直到长度为64。 + +2. 令字符串 ![Data3-inlined]为 + +

+ +

+ +3. 使用 ![Data3-inlined] 通过算法5计算出私钥 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20k_%7BData%5E3%7D) 以及公钥 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20P_%7BData%5E3%7D),并将公钥 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20P_%7BData%5E3%7D) 按照SM2压缩公钥格式以Hex字符串(ASCII编码)的形式输出。得到的Hex字符串记为 ![Data0-inlined]。 + + ![Data0-inlined] 的长度应该为64;若长度不足,则在前面补字符`'0'`,直到长度为64。 + +4. 令字符串 ![UID-inlined]为 + +

+ +

+ +5. 对授权类型 ![LL-inlined] 使用算法4得到签名 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28r_L%2Cs_L%29),其中私钥见第6节。 + + 要求 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_L) 和 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_L) 的长度都不得超过240比特,否则重复该步骤。 + +6. 将 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_L) 和 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_L) 以16进制形式输出(无`"0x"`前缀),分别记为 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Br_L%7D) 和 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bs_L%7D)。 + + 若长度不满60,则在前面补字符`'0'`,直到长度为60。 + +7. 令字符串 ![Data1-inlined]为 + +

+ +

+ +8. 令字符串 ![Temp-inlined]为 + +

+ +

+ + 对 ![Temp-inlined] 使用算法4得到签名 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20%28r_%7BTemp%7D%2Cs_%7BTemp%7D%29),其中私钥见第6节。 + + 要求 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_%7BTemp%7D) 和 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_%7BTemp%7D) 的长度都不得超过240比特,否则重复该步骤。 + +9. 将 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20r_%7BTemp%7D) 和 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20s_%7BTemp%7D) 以16进制形式输出(无`"0x"`前缀),分别记为 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Br_%7BTemp%7D%7D) 和 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bs_%7BTemp%7D%7D)。 + + 若长度不满60,则在前面补字符`'0'`,直到长度为60。 + +10. 令字符串 ![Data2-inlined]为 + +

+ +

+ +11. 对 + +

+ +

+ + 计算CRC32值,最终校验和为CRC32值的反。将校验和以10进制形式输出,若长度不满10,则在前面补字符`'0'`,直到长度为10,记为 ![](http://latex.codecogs.com/svg.latex?%5Cinline%20SZ%5E%7Bchecksum%7D)。 + +12. 令字符串 ![Data-inlined]为 + +

+ +

+ +13. 格式化输出。 + + * 固定文件头`"RAR registration data"`,占一行。 + + * 用户名,占一行。 + + * 授权类型,占一行。 + + * UID,占一行: + +

+ +

+ + * 将 ![Data-inlined] 按照每行54个字符输出。 + diff --git a/README.md b/README.md new file mode 100644 index 0000000..dae921a --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# WinRAR-Keygen + +[中文版 README](README.zh-CN.md) + +icon1 + +## 1. What is WinRAR? + +WinRAR is a trialware file archiver utility for Windows, developed by Eugene Roshal of win.rar GmbH. + +It can create and view archives in RAR or ZIP file formats and unpack numerous archive file formats. + +WinRAR is not a free software. If you want to use it, you should pay to [__RARLAB__](https://rarlab.com/) and then you will get a license file named `rarreg.key`. + +This repository will tell you how WinRAR license file `"rarreg.key"` is generated. + +## 2. How is "rarreg.key" generated? + +See [here](README.HOW_DOES_IT_WORK.md). + +## 3. How to build? + +### 3.1 Prerequisites + +1. Please make sure that you have __Visual Studio 2019__ or the higher. Because this is a VS2019 project. + +2. Please make sure you have installed `vcpkg` and the following libraries: + + * `mpir:x86-windows-static` + * `mpir:x64-windows-static` + + is installed. + + You can install them by: + + ```console + $ vcpkg install mpir:x86-windows-static + $ vcpkg install mpir:x64-windows-static + ``` + +3. Your `vcpkg` has been integrated into your __Visual Studio__, which means you have run + + ```console + $ vcpkg integrate install + ``` + + successfully. + +### 3.2 Build + +1. Open this project in __Visual Studio__. + +2. Select `Release` configuration. + +3. Select __Build > Build Solution__. + +You will see executable files in `bin/` directory. + +## 4. How to Use? + +``` +Usage: + winrar-keygen.exe + +Example: + + winrar-keygen.exe "Rebecca Morrison" "Single PC usage license" + or: + winrar-keygen.exe "Rebecca Morrison" "Single PC usage license" > rarreg.key +``` + +Now you can see the newly generated file. Save the generated information as `rarreg.key`. + +```console +$ winrar-keygen.exe "DoubleLabyrinth" "Single PC usage license" +RAR registration data +DoubleLabyrinth +Single PC usage license +UID=d2fb7cb15c078a3def58 +6412212250ef58bef21cdcb49ca34b7040112cae5a512f1adad1a8 +f6d2ee8c382fe64f8e3d6035c6ab9048e2c5c62f0238f183d28519 +aa87488bf38f5b634cf28190bdf438ac593b1857cdb55a7fcb0eb0 +c3e4c2736090b3dfa45384e08e9de05c5860d3051942adf2db9d96 +e2ec37f1cfae00b3e2455093b90e4e352f016f6b9853c735d45fb4 +01f9cbb91d3f3ac5664511229f8c9b0a9e1d61a2e087b481607e91 +bfc8a83414f6807d31a5f8c587513aa54f9b1249ad804214409316 +``` diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..709c3a3 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,81 @@ +# WinRAR-Keygen + +[README for English](README.md) + +icon1 + +## 1. WinRAR是什么? + +WinRAR是一款用于管理压缩包文件的共享软件。其算法由作者尤金·罗谢尔研发,享有原创专利。 + +它可以用来创建或浏览RAR、ZIP等众多格式的压缩包。 + +WinRAR不是免费的软件。如果你想使用它,你应当向 [__RARLAB__](https://rarlab.com/) 付费,然后获得一个授权文件 `rarreg.key`。 + +这份repo将会告诉你 `rarreg.key` 是如何生成的。 + +## 2. "rarreg.key"是如何生成的? + +见 [这里](README.HOW_DOES_IT_WORK.zh-CN.md)。 + +## 3. 如何编译? + +### 3.1 前提条件 + +1. 请确保你有 __Visual Studio 2019__ 或其更高版本。因为这是一个VS2019项目。 + +2. 请确保你安装了 `vcpkg` 以及下面几个库: + + * `mpir:x86-windows-static` + * `mpir:x64-windows-static` + + 你可以通过下的命令来安装: + + ```console + $ vcpkg install mpir:x86-windows-static + $ vcpkg install mpir:x64-windows-static + ``` + +3. 你的 `vcpkg` 与 __Visual Studio__ 整合了,即你曾成功运行了下面这条命令: + + ```console + $ vcpkg integrate install + ``` + +### 3.2 编译 + +1. 在 __Visual Studio__ 中打开这个项目。 + +2. 选择 `Release` 配置。 + +3. 选择 __生成 > 生成解决方案__。 + +## 4. 如何使用? + +``` +Usage: + winrar-keygen.exe + +Example: + + winrar-keygen.exe "Rebecca Morrison" "Single PC usage license" + or: + winrar-keygen.exe "Rebecca Morrison" "Single PC usage license" > rarreg.key +``` + +现在你可以看到新生成的文件,将生成的信息保存为 `rarreg.key ` 即可: + +```console +$ winrar-keygen.exe "DoubleLabyrinth" "Single PC usage license" +RAR registration data +DoubleLabyrinth +Single PC usage license +UID=d2fb7cb15c078a3def58 +6412212250ef58bef21cdcb49ca34b7040112cae5a512f1adad1a8 +f6d2ee8c382fe64f8e3d6035c6ab9048e2c5c62f0238f183d28519 +aa87488bf38f5b634cf28190bdf438ac593b1857cdb55a7fcb0eb0 +c3e4c2736090b3dfa45384e08e9de05c5860d3051942adf2db9d96 +e2ec37f1cfae00b3e2455093b90e4e352f016f6b9853c735d45fb4 +01f9cbb91d3f3ac5664511229f8c9b0a9e1d61a2e087b481607e91 +bfc8a83414f6807d31a5f8c587513aa54f9b1249ad804214409316 +``` diff --git a/WinRarConfig.hpp b/WinRarConfig.hpp new file mode 100644 index 0000000..4430049 --- /dev/null +++ b/WinRarConfig.hpp @@ -0,0 +1,486 @@ +#pragma once +#include "GaloisField.hpp" +#include "EllipticCurveGF2m.hpp" +#include "BigInteger.hpp" + +struct WinRarConfig { +public: + // Irreducible polynomial of ground field = x^15 + x + 1 + // Irreducible polynomial of extension field = y^17 + y^3 + 1; + struct GF2p15p17Traits { + struct ElementType { + uint16_t Items[17]; + }; + + static constexpr size_t BitSizeValue = 15 * 17; + static constexpr size_t DumpSizeValue = (BitSizeValue + 7) / 8; + + using GF2p15LogExpTableType = uint16_t[0x8000]; + + static const GF2p15LogExpTableType& InitializeGF2p15Table(bool ReturnLogTable) noexcept { + static GF2p15LogExpTableType LogTable; + static GF2p15LogExpTableType ExpTable; + constexpr size_t Order = 0x7fff; + + if (ExpTable[Order] == 0) { + + ExpTable[0] = 1; + for (size_t i = 1; i < Order; ++i) { + uint32_t temp = ExpTable[i - 1] * 2; + if (temp & 0x8000) { + temp ^= 0x8003; + } + ExpTable[i] = temp; + } + + // mark as initialized + ExpTable[Order] = ~ExpTable[Order]; + + for (size_t i = 0; i < Order; ++i) { +// #if defined(_MSC_VER) +// __assume(ExpTable[i] <= Order); +// #endif + LogTable[ExpTable[i]] = static_cast(i); + } + } + + if (ReturnLogTable) { + return LogTable; + } else { + return ExpTable; + } + } + + static inline const GF2p15LogExpTableType& GF2p15LogTable = InitializeGF2p15Table(true); + static inline const GF2p15LogExpTableType& GF2p15ExpTable = InitializeGF2p15Table(false); + static inline const ElementType ZeroValue = {}; + static inline const ElementType OneValue = { 1 }; + + static void Verify(const ElementType& Val) { + for (size_t i = 0; i < 17; ++i) { + if (Val.Items[i] >= 0x8000) { + throw std::invalid_argument("Val is not in GF((2 ^ 15) ^ 17)."); + } + } + } + + static size_t Dump(const ElementType& Val, void* lpBuffer, size_t cbBuffer) { + if (cbBuffer < DumpSizeValue) { + throw std::length_error("Insufficient buffer."); + } else { + uint8_t* pbWritePtr = reinterpret_cast(lpBuffer); + unsigned left_bits = 8; + + for (size_t i = 0; i < 17; ++i) { + uint8_t low8 = static_cast(Val.Items[i]); + uint8_t high7 = static_cast(Val.Items[i] >> 8); + + if (left_bits == 8) { + *pbWritePtr = low8; + ++pbWritePtr; + } else { + *pbWritePtr |= low8 << (8 - left_bits); + ++pbWritePtr; + *pbWritePtr = low8 >> left_bits; + } + + if (left_bits == 8) { + *pbWritePtr = high7; + left_bits = 1; + } else if (left_bits == 7) { + *pbWritePtr |= high7 << 1; + ++pbWritePtr; + left_bits = 8; + } else { + *pbWritePtr |= high7 << (8 - left_bits); + ++pbWritePtr; + *pbWritePtr = high7 >> left_bits; + left_bits = 8 - (7 - left_bits); + } + } + + return DumpSizeValue; + } + } + + static std::vector Dump(const ElementType& Val) noexcept { + std::vector bytes(DumpSizeValue); + Dump(Val, bytes.data(), bytes.size()); + return bytes; + } + + static void Load(ElementType& Val, const void* lpBuffer, size_t cbBuffer) { + if (cbBuffer != DumpSizeValue) { + throw std::length_error("The length of buffer is not correct."); + } else { + const uint8_t* pbBuffer = reinterpret_cast(lpBuffer); + + if (pbBuffer[DumpSizeValue - 1] & 0x80) { + throw std::invalid_argument("Not in GF((2 ^ 15) ^ 17)."); + } + + uint16_t* pbWritePtr = Val.Items; + unsigned left_bits = 15; + + for (size_t i = 0; i < DumpSizeValue; ++i) { + uint16_t v; + if (left_bits == 15) { + v = pbBuffer[i]; + left_bits = 15 - 8; + } else if (left_bits > 8) { + v |= pbBuffer[i] << (15 - left_bits); + left_bits -= 8; + } else { + v |= (pbBuffer[i] << (15 - left_bits)) & 0x7fff; + *pbWritePtr = v; + ++pbWritePtr; + v = pbBuffer[i] >> left_bits; + left_bits = 15 - (8 - left_bits); + } + } + } + } + + static void Load(ElementType& Val, const std::vector& Buffer) { + Load(Val, Buffer.data(), Buffer.size()); + } + + static inline void Swap(ElementType& A, ElementType& B) noexcept { + for (size_t i = 0; i < 17; ++i) { + std::swap(A.Items[i], B.Items[i]); + } + } + + static inline void SetZero(ElementType& Val) noexcept { + memset(Val.Items, 0, sizeof(Val.Items)); + } + + static inline void SetOne(ElementType& Val) noexcept { + Val.Items[0] = 1; + memset(Val.Items + 1, 0, sizeof(Val.Items) - sizeof(Val.Items[0])); + } + + static inline bool IsEqual(const ElementType& A, const ElementType& B) noexcept { + return memcmp(A.Items, B.Items, sizeof(ElementType::Items)) == 0; + } + + static inline bool IsZero(const ElementType& Val) noexcept { + return memcmp(Val.Items, ZeroValue.Items, sizeof(ElementType::Items)) == 0; + } + + static inline bool IsOne(const ElementType& Val) noexcept { + return memcmp(Val.Items, OneValue.Items, sizeof(ElementType::Items)) == 0; + } + + // Result = A + B + static inline void Add(ElementType& Result, const ElementType& A, const ElementType& B) noexcept { + for (size_t i = 0; i < 17; ++i) { + Result.Items[i] = A.Items[i] ^ B.Items[i]; + } + } + + // A += B + static inline void AddAssign(ElementType& A, const ElementType& B) noexcept { + for (size_t i = 0; i < 17; ++i) { + A.Items[i] ^= B.Items[i]; + } + } + + // Result = A + 1 + static inline void AddOne(ElementType& Result, const ElementType& A) noexcept { + Result.Items[0] = A.Items[0] ^ 0x0001; + memcpy(Result.Items + 1, A.Items + 1, sizeof(ElementType::Items) - sizeof(uint16_t)); + } + + // A += 1 + static inline void AddOneAssign(ElementType& A) noexcept { + A.Items[0] ^= 0x0001; + } + + // Result = A - B + static inline void Substract(ElementType& Result, const ElementType& A, const ElementType& B) noexcept { + for (size_t i = 0; i < 17; ++i) { + Result.Items[i] = A.Items[i] ^ B.Items[i]; + } + } + + // A -= B + static inline void SubstractAssign(ElementType& A, const ElementType& B) noexcept { + for (size_t i = 0; i < 17; ++i) { + A.Items[i] ^= B.Items[i]; + } + } + + // Result = A - 1 + static inline void SubstractOne(ElementType& Result, const ElementType& A) noexcept { + Result.Items[0] = A.Items[0] ^ 0x0001; + memcpy(Result.Items + 1, A.Items + 1, sizeof(ElementType::Items) - sizeof(uint16_t)); + } + + // A -= 1 + static inline void SubstractOneAssign(ElementType& A) noexcept { + A.Items[0] ^= 0x0001; + } + + // Result = A * B + // Require: len(Result) == M + N - 1 + static inline void FullMultiplySchoolBook(size_t M, size_t N, uint16_t Result[], const uint16_t A[], const uint16_t B[]) noexcept { + memset(Result, 0, (M + N - 1) * sizeof(uint16_t)); + + for (size_t i = 0; i < M; ++i) { + if (A[i]) { + for (size_t j = 0; j < N; ++j) { + if (B[j]) { + auto g = GF2p15LogTable[A[i]] + GF2p15LogTable[B[j]]; + + if (g >= 0x7fff) { + g -= 0x7fff; + } + + Result[i + j] ^= GF2p15ExpTable[g]; + } + } + } + } + } + + static inline void ModularReduction(size_t N, uint16_t A[]) noexcept { + // Irreducible polynomial of extension field = y^17 + y^3 + 1; + for (size_t i = N - 1; i > 16; --i) { + if (A[i] != 0) { + A[i - 17 + 0] ^= A[i]; + A[i - 17 + 3] ^= A[i]; + A[i] = 0; + } + } + } + + // Result = A * B mod (x^15 + x + 1, y^17 + y^3 + 1) + static inline void Multiply(ElementType& Result, const ElementType& A, const ElementType& B) noexcept { + uint16_t temp[16 + 16 + 1]; + FullMultiplySchoolBook(17, 17, temp, A.Items, B.Items); + ModularReduction(16 + 16 + 1, temp); + memcpy(Result.Items, temp, sizeof(ElementType::Items)); + } + + static inline void MultiplyAssign(ElementType& A, const ElementType& B) noexcept { + Multiply(A, A, B); + } + + static inline void Divide(ElementType& Result, const ElementType& A, const ElementType& B) { + ElementType InverseOfB; + Inverse(InverseOfB, B); + Multiply(Result, A, InverseOfB); + } + + static inline void DivideAssign(ElementType& A, const ElementType& B) { + ElementType InverseOfB; + Inverse(InverseOfB, B); + MultiplyAssign(A, InverseOfB); + } + + static inline void Inverse(ElementType& Result, const ElementType& A) { + // lpA += (Alpha * x ^ j) * B + auto AddScale = [](uint16_t A[], size_t& degA, uint16_t Alpha, size_t j, const uint16_t B[], size_t degB) { + auto logAlpha = GF2p15LogTable[Alpha]; + auto Aj = A + j; + + for (size_t i = 0; i <= degB; ++i) { + if (B[i]) { + auto g = logAlpha + GF2p15LogTable[B[i]]; + + if (g >= 0x7fff) { + g -= 0x7fff; + } + + Aj[i] ^= GF2p15ExpTable[g]; + if (Aj[i] && i + j > degA) { + degA = i + j; + } + } + } + + while (A[degA] == 0) { + --degA; + } + }; + + size_t degB; + size_t degC; + size_t degF; + size_t degG; + uint16_t B[2 * 17]; + uint16_t C[2 * 17]; + uint16_t F[2 * 17]; + uint16_t G[2 * 17]; + + // Initialize B + degB = 0; + B[0] = 1; + memset(B + 1, 0, sizeof(B) - sizeof(uint16_t)); + + // Initialize C + degC = 0; + memset(C, 0, sizeof(C)); + + // Initialize F + bool isZero = true; + for (unsigned i = 0; i < 17; ++i) { + if (A.Items[i] != 0) { + isZero = false; + } + + F[i] = A.Items[i]; + + if (F[i]) { + degF = i; + } + } + memset(F + 17, 0, 17 * sizeof(uint16_t)); + + if (isZero) { + throw std::domain_error("Zero doesn't have inverse."); + } + + // initialize G = x^17 + x^3 + 1; + degG = 17; + memset(G, 0, sizeof(G)); + G[0] = 1; + G[3] = 1; + G[17] = 1; + + for (uint16_t *lpF = F, *lpG = G, *lpB = B, *lpC = C;;) { + if (degF == 0) { + for (size_t i = 0; i <= degB; ++i) { + if (lpB[i]) { + auto g = GF2p15LogTable[lpB[i]] - GF2p15LogTable[lpF[0]]; + + if (g < 0) { + g += 0x7fff; + } + + Result.Items[i] = GF2p15ExpTable[g]; + } else { + Result.Items[i] = 0; + } + } + + for (size_t i = degB + 1; i < 17; ++i) { + Result.Items[i] = 0; + } + + break; + } + + if (degF < degG) { + std::swap(lpF, lpG); + std::swap(degF, degG); + std::swap(lpB, lpC); + std::swap(degB, degC); + } + + auto j = degF - degG; + + auto g = GF2p15LogTable[lpF[degF]] - GF2p15LogTable[lpG[degG]]; + if (g < 0) { + g += 0x7fff; + } + auto Alpha = GF2p15ExpTable[g]; + + AddScale(lpF, degF, Alpha, j, lpG, degG); + AddScale(lpB, degB, Alpha, j, lpC, degC); + } + } + + static inline void InverseAssign(ElementType& Result) { + Inverse(Result, Result); + } + + static inline void Square(ElementType& Result, const ElementType& A) noexcept { + uint16_t temp[16 + 16 + 1]; + + for (size_t i = 0; i < 17; ++i) { + if (A.Items[i]) { + auto g = GF2p15LogTable[A.Items[i]] * 2; + + if (g >= 0x7fff) { + g -= 0x7fff; + } + + temp[2 * i] = GF2p15ExpTable[g]; + } else { + temp[2 * i] = 0; + } + } + + for (size_t i = 1; i < 16 + 16 + 1; i += 2) { + temp[i] = 0; + } + + ModularReduction(16 + 16 + 1, temp); + + memcpy(Result.Items, temp, sizeof(ElementType::Items)); + } + + static inline void SquareAssign(ElementType& A) noexcept { + Square(A, A); + } + }; + + static inline const EllipticCurveGF2m> Curve{ + { GaloisFieldInitByZero{} }, // A + { GaloisFieldInitByElement{}, { 161 } } // B + }; + + static inline const EllipticCurveGF2m>::Point G = Curve.GetPoint( + { + GaloisFieldInitByElement{}, + { + 0x38CC, 0x052F, 0x2510, 0x45AA, + 0x1B89, 0x4468, 0x4882, 0x0D67, + 0x4FEB, 0x55CE, 0x0025, 0x4CB7, + 0x0CC2, 0x59DC, 0x289E, 0x65E3, + 0x56FD + } + }, + { + GaloisFieldInitByElement{}, + { + 0x31A7, 0x65F2, 0x18C4, 0x3412, + 0x7388, 0x54C1, 0x539B, 0x4A02, + 0x4D07, 0x12D6, 0x7911, 0x3B5E, + 0x4F0E, 0x216F, 0x2BF2, 0x1974, + 0x20DA + } + } + ); + + static inline const BigInteger Order = "0x1026dd85081b82314691ced9bbec30547840e4bf72d8b5e0d258442bbcd31"; + + // Generated by `WinRarKeygen::GeneratePrivateKey(nullptr, 0);` + static inline const BigInteger PrivateKey = "0x59fe6abcca90bdb95f0105271fa85fb9f11f467450c1ae9044b7fd61d65e"; + + static inline const EllipticCurveGF2m>::Point PublicKey = Curve.GetPoint( + { + GaloisFieldInitByElement{}, + { + 0x3A1A, 0x1109, 0x268A, 0x12F7, + 0x3734, 0x75F0, 0x576C, 0x2EA4, + 0x4813, 0x3F62, 0x0567, 0x784D, + 0x753D, 0x6D92, 0x366C, 0x1107, + 0x3861 + } + }, + { + GaloisFieldInitByElement{}, + { + 0x6C20, 0x6027, 0x1B22, 0x7A87, + 0x43C4, 0x1908, 0x2449, 0x4675, + 0x7933, 0x2E66, 0x32F5, 0x2A58, + 0x1145, 0x74AC, 0x36D0, 0x2731, + 0x12B6 + } + } + ); +}; + diff --git a/WinRarKeygen.hpp b/WinRarKeygen.hpp new file mode 100644 index 0000000..2eb42da --- /dev/null +++ b/WinRarKeygen.hpp @@ -0,0 +1,233 @@ +#pragma once +#include "BigInteger.hpp" +#include "Hasher.hpp" +#include "HasherSha1Traits.hpp" +#include "HasherCrc32Traits.hpp" +#include +#include +#include +#include +#include + +template +class WinRarKeygen { +public: + + struct RegisterInfo { + std::string UserName; + std::string LicenseType; + std::string UID; + std::string Items[4]; + uint32_t Checksum; + std::string HexData; + }; + +private: + + struct ECCSignature { + BigInteger r; + BigInteger s; + }; + + static BigInteger GeneratePrivateKey(const void* lpSeed, size_t cbSeed) { + uint32_t Generator[6]; + uint16_t RawPrivateKey[15] = {}; + + if (cbSeed) { + Hasher Sha1(HasherSha1Traits{}, lpSeed, cbSeed); + HasherSha1Traits::DigestType Sha1Digest; + + Sha1Digest = Sha1.Evaluate(); + + for (unsigned i = 0; i < 5; ++i) { + Generator[i + 1] = _byteswap_ulong(reinterpret_cast(Sha1Digest.Bytes)[i]); + } + } else { + Generator[1] = 0xeb3eb781; + Generator[2] = 0x50265329; + Generator[3] = 0xdc5ef4a3; + Generator[4] = 0x6847b9d5; + Generator[5] = 0xcde43b4c; + } + + for (uint32_t i = 0; i < 15; ++i) { + Hasher Sha1(HasherSha1Traits{}); + HasherSha1Traits::DigestType Sha1Digest; + + Generator[0] = i + 1; + Sha1.Update(Generator, sizeof(Generator)); + Sha1Digest = Sha1.Evaluate(); + + RawPrivateKey[i] = static_cast( + _byteswap_ulong(reinterpret_cast(Sha1Digest.Bytes)[0]) + ); + } + + // `Order` has 241 bits, while `RawPrivateKey` has (15 * 16 = 240) bits at most + // So `RawPrivateKey` must be less than `Order` which means `RawPrivateKey` must be valid private key. + return BigInteger(false, RawPrivateKey, sizeof(RawPrivateKey), true); + } + + static auto GeneratePublicKey(const BigInteger& PrivateKey) { + return __ConfigType::G * PrivateKey; + } + + static std::string GeneratePublicKeySM2CompressedFormat(const char* lpszMessage) { + auto PrivateKey = GeneratePrivateKey(lpszMessage, strlen(lpszMessage)); + auto PublicKey = GeneratePublicKey(PrivateKey); + auto PublicKeyCompressed = PublicKey.DumpCompressed(); + auto PublicKeyXInteger = BigInteger(false, PublicKeyCompressed.data() + 1, PublicKeyCompressed.size() - 1, false); // 255 bits at most + + PublicKeyXInteger *= 2; // 256 bits at most + if (PublicKeyCompressed[0] == 0x03) { // when LSB(PublicKeyY / PublicKeyX) == 1 + PublicKeyXInteger.SetBit(0); + } + + auto PublicKeyCompressedSM2Format = PublicKeyXInteger.ToString(16, true); + if (PublicKeyCompressedSM2Format.length() < 32 * 2) { + PublicKeyCompressedSM2Format.insert(PublicKeyCompressedSM2Format.begin(), 32 * 2 - PublicKeyCompressedSM2Format.size(), '0'); + } + + return PublicKeyCompressedSM2Format; + } + + static BigInteger GenerateRandomInteger() { + uint16_t RawRandomInteger[15]; + + srand(static_cast(time(nullptr))); + for (size_t i = 0; i < 15; ++i) { + RawRandomInteger[i] = static_cast(rand()); + } + + return BigInteger(false, RawRandomInteger, sizeof(RawRandomInteger), true); + } + + static BigInteger GenerateHashInteger(const void* lpMessage, size_t cbMessage) { + uint32_t RawHash[10]; + Hasher Sha1(HasherSha1Traits{}, lpMessage, cbMessage); + HasherSha1Traits::DigestType Sha1Digest = Sha1.Evaluate(); + + for (size_t i = 0; i < 5; ++i) { + RawHash[i] = _byteswap_ulong(reinterpret_cast(Sha1Digest.Bytes)[i]); + } + + // SHA1("") with all-zeroed initial value + RawHash[5] = 0x0ffd8d43; + RawHash[6] = 0xb4e33c7c; + RawHash[7] = 0x53461bd1; + RawHash[8] = 0x0f27a546; + RawHash[9] = 0x1050d90d; + + return BigInteger(false, RawHash, 15 * sizeof(uint16_t), true); // take first 240 bits + } + + static ECCSignature Sign(const void* lpData, size_t cbData) { + ECCSignature Signature; + BigInteger Hash = GenerateHashInteger(lpData, cbData); + + while (true) { + BigInteger Random = GenerateRandomInteger(); + + // + // Calculate Signature.r + // + Signature.r.Load(false, (__ConfigType::G * Random).GetX().Dump(), true); + Signature.r += Hash; + Signature.r %= __ConfigType::Order; + if (Signature.r.IsZero() || Signature.r + Random == __ConfigType::Order) { + continue; + } + + // + // Calculate Signature.s + // + Signature.s = Random - __ConfigType::PrivateKey * Signature.r; + Signature.s %= __ConfigType::Order; + if (Signature.s.IsZero()) { + continue; + } + + break; + } + + return Signature; + } + + static void CalculateChecksum(RegisterInfo& Info) { + Hasher Crc32(HasherCrc32Traits<0xEDB88320>{}); + Crc32.Update(Info.LicenseType.c_str(), Info.LicenseType.length()); + Crc32.Update(Info.UserName.c_str(), Info.UserName.length()); + Crc32.Update(Info.Items[0].c_str(), Info.Items[0].length()); + Crc32.Update(Info.Items[1].c_str(), Info.Items[1].length()); + Crc32.Update(Info.Items[2].c_str(), Info.Items[2].length()); + Crc32.Update(Info.Items[3].c_str(), Info.Items[3].length()); + Info.Checksum = ~Crc32.Evaluate(); + } +public: + + template + static inline std::string HelperStringFormat(const char* lpszFormat, ArgTypes&& ... Args) { + std::string s(snprintf(nullptr, 0, lpszFormat, std::forward(Args)...) + 1, '\x00'); + + snprintf(s.data(), s.size(), lpszFormat, std::forward(Args)...); + while (s.back() == '\x00') { + s.pop_back(); + } + + return s; + } + + static RegisterInfo GenerateRegisterInfo(const char* lpszUserName, const char* lpszLicenseType) { + RegisterInfo RegInfo; + std::string temp; + + RegInfo.UserName = lpszUserName; + RegInfo.LicenseType = lpszLicenseType; + + temp = GeneratePublicKeySM2CompressedFormat(lpszUserName); + RegInfo.Items[3] = HelperStringFormat("60%.48s", temp.c_str()); + RegInfo.Items[0] = GeneratePublicKeySM2CompressedFormat(RegInfo.Items[3].c_str()); + RegInfo.UID = HelperStringFormat("%.16s%.4s", temp.c_str() + 48, RegInfo.Items[0].c_str()); + + while (true) { + auto LicenseTypeSignature = Sign(RegInfo.LicenseType.c_str(), RegInfo.LicenseType.length()); + auto LicenseTypeSignatureR = LicenseTypeSignature.r.ToString(16, true); + auto LicenseTypeSignatureS = LicenseTypeSignature.s.ToString(16, true); + if (LicenseTypeSignatureR.length() <= 60 && LicenseTypeSignatureS.length() <= 60) { + RegInfo.Items[1] = HelperStringFormat("60%060s%060s", LicenseTypeSignatureS.c_str(), LicenseTypeSignatureR.c_str()); + break; + } + } + + temp = RegInfo.UserName + RegInfo.Items[0]; + while (true) { + auto UserNameSignature = Sign(temp.c_str(), temp.length()); + auto UserNameSignatureR = UserNameSignature.r.ToString(16, true); + auto UserNameSignatureS = UserNameSignature.s.ToString(16, true); + if (UserNameSignatureR.length() <= 60 || UserNameSignatureS.length() <= 60) { + RegInfo.Items[2] = HelperStringFormat("60%060s%060s", UserNameSignatureS.c_str(), UserNameSignatureR.c_str()); + break; + } + } + + CalculateChecksum(RegInfo); + + RegInfo.HexData = HelperStringFormat( + "%zd%zd%zd%zd%s%s%s%s%010lu", + RegInfo.Items[0].length(), + RegInfo.Items[1].length(), + RegInfo.Items[2].length(), + RegInfo.Items[3].length(), + RegInfo.Items[0].c_str(), + RegInfo.Items[1].c_str(), + RegInfo.Items[2].c_str(), + RegInfo.Items[3].c_str(), + RegInfo.Checksum + ); + if (RegInfo.HexData.length() % 54 != 0) { + throw std::runtime_error("InternalError: The length of register data is not correct."); + } + + return RegInfo; + } +}; diff --git a/_tmain.cpp b/_tmain.cpp new file mode 100644 index 0000000..6c85584 --- /dev/null +++ b/_tmain.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include "WinRarConfig.hpp" +#include "WinRarKeygen.hpp" +#include + +void Help() { + _putts(TEXT("Usage:")); + _putts(TEXT(" winrar-keygen.exe ")); + _putts(TEXT("")); + _putts(TEXT("Example:")); + _putts(TEXT("")); + _putts(TEXT(" winrar-keygen.exe \"Rebecca Morrison\" \"Single PC usage license\"")); + _putts(TEXT(" or:")); + _putts(TEXT(" winrar-keygen.exe \"Rebecca Morrison\" \"Single PC usage license\" > rarreg.key\n")); +} + +void PrintRegisterInfo(const WinRarKeygen::RegisterInfo& Info) { + _tprintf_s(TEXT("%hs\n"), "RAR registration data"); + _tprintf_s(TEXT("%hs\n"), Info.UserName.c_str()); + _tprintf_s(TEXT("%hs\n"), Info.LicenseType.c_str()); + _tprintf_s(TEXT("UID=%hs\n"), Info.UID.c_str()); + for (size_t i = 0; i < Info.HexData.length(); i += 54) { + _tprintf_s(TEXT("%.54hs\n"), Info.HexData.c_str() + i); + } +} + +std::string ToACP(PCWSTR lpszUnicodeString) { + int len; + + len = WideCharToMultiByte(CP_ACP, 0, lpszUnicodeString, -1, NULL, 0, NULL, NULL); + if (len == 0) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + + std::string Result(len, '\x00'); + + len = WideCharToMultiByte(CP_ACP, 0, lpszUnicodeString, -1, Result.data(), static_cast(Result.length()), NULL, NULL); + if (len == 0) { + auto err = GetLastError(); + throw std::system_error(err, std::system_category()); + } + + while (Result.back() == '\x00') { + Result.pop_back(); + } + + return Result; +} + +int _tmain(int argc, PTSTR argv[]) { + setlocale(LC_ALL, ""); + if (argc == 3) { + try { + PrintRegisterInfo( +#if defined(_UNICODE) || defined(UNICODE) + WinRarKeygen::GenerateRegisterInfo(ToACP(argv[1]).c_str(), ToACP(argv[2]).c_str()) +#else + WinRarKeygen::GenerateRegisterInfo(argv[1], argv[2]) +#endif + ); + } catch (std::exception& e) { + _tprintf_s(TEXT("%hs\n"), e.what()); + return -1; + } + } else { + Help(); + } + return 0; +} + diff --git a/bin/x64-Release/winrar-keygen.exe b/bin/x64-Release/winrar-keygen.exe new file mode 100644 index 0000000..51ba400 Binary files /dev/null and b/bin/x64-Release/winrar-keygen.exe differ diff --git a/bin/x64-Release/winrar-keygen.iobj b/bin/x64-Release/winrar-keygen.iobj new file mode 100644 index 0000000..50dae4d Binary files /dev/null and b/bin/x64-Release/winrar-keygen.iobj differ diff --git a/bin/x64-Release/winrar-keygen.ipdb b/bin/x64-Release/winrar-keygen.ipdb new file mode 100644 index 0000000..89b30a0 Binary files /dev/null and b/bin/x64-Release/winrar-keygen.ipdb differ diff --git a/bin/x64-Release/winrar-keygen.pdb b/bin/x64-Release/winrar-keygen.pdb new file mode 100644 index 0000000..e3f03f8 Binary files /dev/null and b/bin/x64-Release/winrar-keygen.pdb differ diff --git a/icon1.ico b/icon1.ico new file mode 100644 index 0000000..3c3aa43 Binary files /dev/null and b/icon1.ico differ diff --git a/icon1.png b/icon1.png new file mode 100644 index 0000000..b72ebdd Binary files /dev/null and b/icon1.png differ diff --git a/obj/x64-Debug/vc142.idb b/obj/x64-Debug/vc142.idb new file mode 100644 index 0000000..3702ef1 Binary files /dev/null and b/obj/x64-Debug/vc142.idb differ diff --git a/obj/x64-Debug/vc142.pdb b/obj/x64-Debug/vc142.pdb new file mode 100644 index 0000000..89bf5cf Binary files /dev/null and b/obj/x64-Debug/vc142.pdb differ diff --git a/obj/x64-Debug/winrar-keygen.Build.CppClean.log b/obj/x64-Debug/winrar-keygen.Build.CppClean.log new file mode 100644 index 0000000..e69de29 diff --git a/obj/x64-Debug/winrar-keygen.log b/obj/x64-Debug/winrar-keygen.log new file mode 100644 index 0000000..01c8218 --- /dev/null +++ b/obj/x64-Debug/winrar-keygen.log @@ -0,0 +1,2 @@ + _tmain.cpp +D:\Users\haoning\Documents\Visual Studio 2019\winrar-keygen\BigInteger.hpp(4,10): fatal error C1083: 无法打开包括文件: “gmp.h”: No such file or directory diff --git a/obj/x64-Debug/winrar-keygen.tlog/CL.command.1.tlog b/obj/x64-Debug/winrar-keygen.tlog/CL.command.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/obj/x64-Debug/winrar-keygen.tlog/CL.command.1.tlog @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/obj/x64-Debug/winrar-keygen.tlog/unsuccessfulbuild b/obj/x64-Debug/winrar-keygen.tlog/unsuccessfulbuild new file mode 100644 index 0000000..e69de29 diff --git a/obj/x64-Debug/winrar-keygen.tlog/winrar-keygen.lastbuildstate b/obj/x64-Debug/winrar-keygen.tlog/winrar-keygen.lastbuildstate new file mode 100644 index 0000000..8c87621 --- /dev/null +++ b/obj/x64-Debug/winrar-keygen.tlog/winrar-keygen.lastbuildstate @@ -0,0 +1,2 @@ +PlatformToolSet=v142:VCToolArchitecture=Native32Bit:VCToolsVersion=14.27.29110:TargetPlatformVersion=10.0.18362.0: +Debug|x64|D:\Users\haoning\Documents\Visual Studio 2019\winrar-keygen\| diff --git a/obj/x64-Debug/winrar-keygen.vcxproj.FileListAbsolute.txt b/obj/x64-Debug/winrar-keygen.vcxproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29 diff --git a/obj/x64-Release/_tmain.obj b/obj/x64-Release/_tmain.obj new file mode 100644 index 0000000..c03b341 Binary files /dev/null and b/obj/x64-Release/_tmain.obj differ diff --git a/obj/x64-Release/vc142.pdb b/obj/x64-Release/vc142.pdb new file mode 100644 index 0000000..77113d1 Binary files /dev/null and b/obj/x64-Release/vc142.pdb differ diff --git a/obj/x64-Release/vcpkg.applocal.log b/obj/x64-Release/vcpkg.applocal.log new file mode 100644 index 0000000..e02abfc --- /dev/null +++ b/obj/x64-Release/vcpkg.applocal.log @@ -0,0 +1 @@ + diff --git a/obj/x64-Release/winrar-keygen.Build.CppClean.log b/obj/x64-Release/winrar-keygen.Build.CppClean.log new file mode 100644 index 0000000..a015907 --- /dev/null +++ b/obj/x64-Release/winrar-keygen.Build.CppClean.log @@ -0,0 +1,18 @@ +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\vc142.pdb +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\_tmain.obj +d:\users\haoning\documents\visual studio 2019\winrar-keygen\bin\x64-release\winrar-keygen.exe +d:\users\haoning\documents\visual studio 2019\winrar-keygen\bin\x64-release\winrar-keygen.pdb +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.res +d:\users\haoning\documents\visual studio 2019\winrar-keygen\bin\x64-release\winrar-keygen.ipdb +d:\users\haoning\documents\visual studio 2019\winrar-keygen\bin\x64-release\winrar-keygen.iobj +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\vcpkg.applocal.log +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\cl.command.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\cl.read.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\cl.write.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\link.command.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\link.read.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\link.write.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\rc.command.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\rc.read.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\rc.write.1.tlog +d:\users\haoning\documents\visual studio 2019\winrar-keygen\obj\x64-release\winrar-keygen.tlog\winrar-keygen.write.1u.tlog diff --git a/obj/x64-Release/winrar-keygen.exe.recipe b/obj/x64-Release/winrar-keygen.exe.recipe new file mode 100644 index 0000000..9868a88 --- /dev/null +++ b/obj/x64-Release/winrar-keygen.exe.recipe @@ -0,0 +1,7 @@ + + + D:\Users\haoning\Documents\Visual Studio 2019\winrar-keygen\bin\x64-Release\winrar-keygen.exe + + + + \ No newline at end of file diff --git a/obj/x64-Release/winrar-keygen.log b/obj/x64-Release/winrar-keygen.log new file mode 100644 index 0000000..3a17d38 --- /dev/null +++ b/obj/x64-Release/winrar-keygen.log @@ -0,0 +1,6 @@ + _tmain.cpp + 正在生成代码 + Previous IPDB not found, fall back to full compilation. + All 409 functions were compiled because no usable IPDB/IOBJ from previous compilation was found. + 已完成代码的生成 + winrar-keygen.vcxproj -> D:\Users\haoning\Documents\Visual Studio 2019\winrar-keygen\bin\x64-Release\winrar-keygen.exe diff --git a/obj/x64-Release/winrar-keygen.res b/obj/x64-Release/winrar-keygen.res new file mode 100644 index 0000000..ee88311 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.res differ diff --git a/obj/x64-Release/winrar-keygen.tlog/CL.command.1.tlog b/obj/x64-Release/winrar-keygen.tlog/CL.command.1.tlog new file mode 100644 index 0000000..c9c0674 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/CL.command.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/CL.read.1.tlog b/obj/x64-Release/winrar-keygen.tlog/CL.read.1.tlog new file mode 100644 index 0000000..dfaf434 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/CL.read.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/CL.write.1.tlog b/obj/x64-Release/winrar-keygen.tlog/CL.write.1.tlog new file mode 100644 index 0000000..d2abc6d Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/CL.write.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/link.command.1.tlog b/obj/x64-Release/winrar-keygen.tlog/link.command.1.tlog new file mode 100644 index 0000000..70085a2 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/link.command.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/link.read.1.tlog b/obj/x64-Release/winrar-keygen.tlog/link.read.1.tlog new file mode 100644 index 0000000..ae0858b Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/link.read.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/link.write.1.tlog b/obj/x64-Release/winrar-keygen.tlog/link.write.1.tlog new file mode 100644 index 0000000..4542992 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/link.write.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/rc.command.1.tlog b/obj/x64-Release/winrar-keygen.tlog/rc.command.1.tlog new file mode 100644 index 0000000..efd94d4 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/rc.command.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/rc.read.1.tlog b/obj/x64-Release/winrar-keygen.tlog/rc.read.1.tlog new file mode 100644 index 0000000..d21fad1 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/rc.read.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/rc.write.1.tlog b/obj/x64-Release/winrar-keygen.tlog/rc.write.1.tlog new file mode 100644 index 0000000..d2ed052 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/rc.write.1.tlog differ diff --git a/obj/x64-Release/winrar-keygen.tlog/winrar-keygen.lastbuildstate b/obj/x64-Release/winrar-keygen.tlog/winrar-keygen.lastbuildstate new file mode 100644 index 0000000..9d5a859 --- /dev/null +++ b/obj/x64-Release/winrar-keygen.tlog/winrar-keygen.lastbuildstate @@ -0,0 +1,2 @@ +PlatformToolSet=v142:VCToolArchitecture=Native32Bit:VCToolsVersion=14.27.29110:TargetPlatformVersion=10.0.18362.0: +Release|x64|D:\Users\haoning\Documents\Visual Studio 2019\winrar-keygen\| diff --git a/obj/x64-Release/winrar-keygen.tlog/winrar-keygen.write.1u.tlog b/obj/x64-Release/winrar-keygen.tlog/winrar-keygen.write.1u.tlog new file mode 100644 index 0000000..286a287 Binary files /dev/null and b/obj/x64-Release/winrar-keygen.tlog/winrar-keygen.write.1u.tlog differ diff --git a/obj/x64-Release/winrar-keygen.vcxproj.FileListAbsolute.txt b/obj/x64-Release/winrar-keygen.vcxproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29 diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..41e4b5b --- /dev/null +++ b/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ ɵİļ +// winrar-keygen.rc ʹ +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/winrar-keygen.aps b/winrar-keygen.aps new file mode 100644 index 0000000..39b7d61 Binary files /dev/null and b/winrar-keygen.aps differ diff --git a/winrar-keygen.rc b/winrar-keygen.rc new file mode 100644 index 0000000..f4583f6 --- /dev/null +++ b/winrar-keygen.rc @@ -0,0 +1,110 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// (壬й) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "icon1.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "GmbH" + VALUE "FileDescription", "GmbH Keygen Tool" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "winrar-keygen.exe" + VALUE "LegalCopyright", "Copyright (C) 2020" + VALUE "OriginalFilename", "winrar-k.exe" + VALUE "ProductName", "WinRAR Keygen" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // (壬й) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/winrar-keygen.sln b/winrar-keygen.sln new file mode 100644 index 0000000..d5ffe5e --- /dev/null +++ b/winrar-keygen.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29009.5 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winrar-keygen", "winrar-keygen.vcxproj", "{2443AA55-9534-4451-9BCC-48AC0982A0CC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Debug|x64.ActiveCfg = Debug|x64 + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Debug|x64.Build.0 = Debug|x64 + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Debug|x86.ActiveCfg = Debug|Win32 + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Debug|x86.Build.0 = Debug|Win32 + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Release|x64.ActiveCfg = Release|x64 + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Release|x64.Build.0 = Release|x64 + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Release|x86.ActiveCfg = Release|Win32 + {2443AA55-9534-4451-9BCC-48AC0982A0CC}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {382D4DCF-4617-437C-B855-01180D3AF852} + EndGlobalSection +EndGlobal diff --git a/winrar-keygen.vcxproj b/winrar-keygen.vcxproj new file mode 100644 index 0000000..e33d37f --- /dev/null +++ b/winrar-keygen.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {2443AA55-9534-4451-9BCC-48AC0982A0CC} + Win32Proj + winrarkeygen + 10.0 + x86-windows-static + x64-windows-static + + + + Application + true + v142 + Unicode + false + + + Application + false + v142 + true + Unicode + false + + + Application + true + v142 + Unicode + false + + + Application + false + v142 + true + Unicode + false + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)bin\$(Platform)-$(Configuration)\ + $(SolutionDir)obj\$(Platform)-$(Configuration)\ + + + true + $(SolutionDir)bin\$(Platform)-$(Configuration)\ + $(SolutionDir)obj\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)bin\$(Platform)-$(Configuration)\ + $(SolutionDir)obj\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)bin\$(Platform)-$(Configuration)\ + $(SolutionDir)obj\$(Platform)-$(Configuration)\ + + + + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + MultiThreadedDebug + + + Console + true + + + + + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + MultiThreadedDebug + + + Console + true + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + MultiThreaded + + + Console + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + MultiThreaded + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/winrar-keygen.vcxproj.filters b/winrar-keygen.vcxproj.filters new file mode 100644 index 0000000..68e85f4 --- /dev/null +++ b/winrar-keygen.vcxproj.filters @@ -0,0 +1,61 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + 资源文件 + + + + + 资源文件 + + + \ No newline at end of file diff --git a/winrar-keygen.vcxproj.user b/winrar-keygen.vcxproj.user new file mode 100644 index 0000000..966b4ff --- /dev/null +++ b/winrar-keygen.vcxproj.user @@ -0,0 +1,6 @@ + + + + true + + \ No newline at end of file