code:
#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<uint16_t>(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<uint8_t*>(lpBuffer);
                unsigned left_bits = 8;

                for (size_t i = 0; i < 17; ++i) {
                    uint8_t low8 = static_cast<uint8_t>(Val.Items[i]);
                    uint8_t high7 = static_cast<uint8_t>(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<uint8_t> Dump(const ElementType& Val) noexcept {
            std::vector<uint8_t> 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<const uint8_t*>(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<uint8_t>& 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<GaloisField<GF2p15p17Traits>> Curve{
        { GaloisFieldInitByZero{} },                // A
        { GaloisFieldInitByElement{}, { 161 } }     // B
    };

    static inline const EllipticCurveGF2m<GaloisField<GF2p15p17Traits>>::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<WinRarConfig>::GeneratePrivateKey(nullptr, 0);`
    static inline const BigInteger PrivateKey = "0x59fe6abcca90bdb95f0105271fa85fb9f11f467450c1ae9044b7fd61d65e";

    static inline const EllipticCurveGF2m<GaloisField<GF2p15p17Traits>>::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
            }
        }
    );
};


code:
#pragma once
#include "BigInteger.hpp"
#include "Hasher.hpp"
#include "HasherSha1Traits.hpp"
#include "HasherCrc32Traits.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string>
#include <utility>

#ifndef _WIN32
#define _byteswap_ulong __builtin_bswap32
#endif

template<typename __ConfigType>
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<uint32_t*>(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<uint16_t>(
                _byteswap_ulong(reinterpret_cast<uint32_t*>(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<unsigned int>(time(nullptr)));
        for (size_t i = 0; i < 15; ++i) {
            RawRandomInteger[i] = static_cast<uint16_t>(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<uint32_t*>(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<typename... ArgTypes>
    static inline std::string HelperStringFormat(const char* lpszFormat, ArgTypes&& ... Args) {
        std::string s(snprintf(nullptr, 0, lpszFormat, std::forward<ArgTypes>(Args)...) + 1, '\x00');

        snprintf(s.data(), s.size(), lpszFormat, std::forward<ArgTypes>(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;
    }
};

#ifndef _WIN32
#undef _byteswap_ulong
#endif

repo_name: lichendaozhu/winrar

license: unknown


code:
#ifdef _WIN32
#include <tchar.h>
#include <windows.h>
#ifdef __GNUC__
#define MINGW_HAS_SECURE_API
#include <sec_api/stdio_s.h>
#define _tprintf_s printf_s
#endif
#define HS "hs"
#else
#define PTSTR char*
#define _putts puts
#define _tprintf_s printf
#define TEXT(s) s
#define HS "s"
#endif
#include <stdio.h>
#include <locale.h>
#include "WinRarConfig.hpp"
#include "WinRarKeygen.hpp"
#include <system_error>

void Help() {
    _putts(TEXT("Usage:"));
    _putts(TEXT("        winrar-keygen.exe <your name> <license type>"));
    _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<WinRarConfig>::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("%.54" HS "\n"), Info.HexData.c_str() + i);
    }
}

#ifdef _WIN32
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<int>(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;
}
#endif

#ifdef WIN32
int _tmain(int argc, PTSTR argv[]) {
#else
int main(int argc, PTSTR argv[]) {
#endif
    setlocale(LC_ALL, "");
    if (argc == 3) {
        try {
            PrintRegisterInfo(
#if defined(_UNICODE) || defined(UNICODE)
                WinRarKeygen<WinRarConfig>::GenerateRegisterInfo(ToACP(argv[1]).c_str(), ToACP(argv[2]).c_str())
#else
                WinRarKeygen<WinRarConfig>::GenerateRegisterInfo(argv[1], argv[2])
#endif
            );
        } catch (std::exception& e) {
            _tprintf_s(TEXT("%" HS "\n"), e.what());
            return -1;
        }
    } else {
        Help();
    }
    return 0;
}


code:
[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?

[中文版](how-does-it-work.zh-CN.md)

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

    <img src="http://latex.codecogs.com/svg.latex?P%28%5Calpha%29%3D%5Calpha%5E%7B15%7D+%5Calpha+1")

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

    <img src="http://latex.codecogs.com/svg.latex?B_1%3D%5C%7B1%2C%5Calpha%2C%5Calpha%5E2%2C%5Cldots%2C%5Calpha%5E%7B14%7D%5C%7D")

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

    <img src="http://latex.codecogs.com/svg.latex?A%3D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_i%5Calpha%5Ei%20%5Cquad%20%5Cquad%20%5Cquad%20a_i%5Cin%5Ctextrm%7BGF%7D%282%29")

---

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

    <img src="http://latex.codecogs.com/svg.latex?Q%28%5Cbeta%29%3D%5Cbeta%5E%7B17%7D+%5Cbeta%5E3+1")

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

    <img src="http://latex.codecogs.com/svg.latex?B_2%3D%5C%7B1%2C%5Cbeta%2C%5Cbeta%5E2%2C%5Cldots%2C%5Cbeta%5E%7B16%7D%5C%7D")

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

    <img src="http://latex.codecogs.com/svg.latex?B%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%28%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Calpha%5Ei%29%5Cbeta%5Ej%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Calpha%5Ei%5Cbeta%5Ej%20%5Cquad%20%5Cquad%20%5Cquad%20a_%7Bj%2Ci%7D%5Cin%5Ctextrm%7BGF%7D%282%29")

---

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

    <img src="http://latex.codecogs.com/svg.latex?B%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Calpha%5Ei%5Cbeta%5Ej%20%5Cleftrightarrow%20D%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Ccdot%202%5E%7B15j+i%7D")

## 2. Elliptic curve over ![GF2p15p17-inlined]

The equation of the elliptic curve that WinRAR uses is

    <img src="http://latex.codecogs.com/svg.latex?y%5E2+xy%3Dx%5E3+161%20%5Cquad%20%5Cquad%20%5Cquad%20161%5Cin%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29")

The base point ![G-inlined] is

    <img src="http://latex.codecogs.com/svg.latex?%5Cbegin%7Baligned%7D%20G%26%3D%28G_x%2CG_y%29%20%5C%5C%20G_x%26%3D%5Ctextrm%7B0x56fdcbc6a27acee0cc2996e0096ae74feb1acf220a2341b898b549440297b8cc%7D%20%5Cquad%20G_x%5Cin%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29%5C%5C%20G_y%26%3D%5Ctextrm%7B0x20da32e8afc90b7cf0e76bde44496b4d0794054e6ea60f388682463132f931a7%7D%20%5Cquad%20G_y%5Cin%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29%20%5Cend%7Baligned%7D")

whose order ![n-inlined] is

    <img src="http://latex.codecogs.com/svg.latex?n%3D%5Ctextrm%7B0x1026dd85081b82314691ced9bbec30547840e4bf72d8b5e0d258442bbcd31%7D%20%5Cquad%20n%5Cin%5Cnolinebreak%5Cmathbb%7BZ%7D")

## 3. Message hash algorithm

We use

    <img src="http://latex.codecogs.com/svg.latex?M%3Dm_0m_1%20%5Cldots%20m_%7Bl-1%7D%20%5Cquad%20%5Cquad%20m_i%5Cin%5B0%2C%20256%29")

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

    <img src="http://latex.codecogs.com/svg.latex?%5Ctextrm%7BSHA%7D_1%28M%29%3DS_0%7C%7CS_1%7C%7CS_2%7C%7CS_3%7C%7CS_4%20%5Cquad%20%5Cquad%20S_i%5Cin%5B0%2C%202%5E%7B32%7D%29")

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.

    <img src="http://latex.codecogs.com/svg.latex?h%3D%28%5Csum_%7Bi%3D0%7D%5E%7B4%7DS_i%20%5Ccdot%202%5E%7B32i%7D%29+%5Ctextrm%7B0x1bd10xb4e33c7c0ffd8d43%7D%20%5Ccdot%202%5E%7B32*5%7D")

## 4. ECC digital signature algorithm

We use ![k-inlined] to denote private key, ![P-inlined] to denote public key. So there must be

    <img src="http://latex.codecogs.com/svg.latex?P%3Dk%20%5Ccdot%20G")

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.


code:
[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] 采用标准基（多项式基）来表达，采用的不可约多项式为：

    <img src="http://latex.codecogs.com/svg.latex?P%28%5Calpha%29%3D%5Calpha%5E%7B15%7D+%5Calpha+1")

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

    <img src="http://latex.codecogs.com/svg.latex?B_1%3D%5C%7B1%2C%5Calpha%2C%5Calpha%5E2%2C%5Cldots%2C%5Calpha%5E%7B14%7D%5C%7D")

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

    <img src="http://latex.codecogs.com/svg.latex?A%3D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_i%5Calpha%5Ei%20%5Cquad%20%5Cquad%20%5Cquad%20a_i%5Cin%5Ctextrm%7BGF%7D%282%29")

---

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

    <img src="http://latex.codecogs.com/svg.latex?Q%28%5Cbeta%29%3D%5Cbeta%5E%7B17%7D+%5Cbeta%5E3+1")

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

    <img src="http://latex.codecogs.com/svg.latex?B_2%3D%5C%7B1%2C%5Cbeta%2C%5Cbeta%5E2%2C%5Cldots%2C%5Cbeta%5E%7B16%7D%5C%7D")

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

    <img src="http://latex.codecogs.com/svg.latex?B%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%28%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Calpha%5Ei%29%5Cbeta%5Ej%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Calpha%5Ei%5Cbeta%5Ej%20%5Cquad%20%5Cquad%20%5Cquad%20a_%7Bj%2Ci%7D%5Cin%5Ctextrm%7BGF%7D%282%29")

---

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

    <img src="http://latex.codecogs.com/svg.latex?B%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Calpha%5Ei%5Cbeta%5Ej%20%5Cleftrightarrow%20D%3D%5Csum_%7Bj%3D0%7D%5E%7B16%7D%5Csum_%7Bi%3D0%7D%5E%7B14%7Da_%7Bj%2Ci%7D%5Ccdot%202%5E%7B15j+i%7D")

## 2. 复合域 ![GF2p15p17-inlined] 上的椭圆曲线

曲线方程为：

    <img src="http://latex.codecogs.com/svg.latex?y%5E2+xy%3Dx%5E3+161%20%5Cquad%20%5Cquad%20%5Cquad%20161%5Cin%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29")

基点 ![G-inlined] 为：

    <img src="http://latex.codecogs.com/svg.latex?%5Cbegin%7Baligned%7D%20G%26%3D%28G_x%2CG_y%29%20%5C%5C%20G_x%26%3D%5Ctextrm%7B0x56fdcbc6a27acee0cc2996e0096ae74feb1acf220a2341b898b549440297b8cc%7D%20%5Cquad%20G_x%5Cin%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29%5C%5C%20G_y%26%3D%5Ctextrm%7B0x20da32e8afc90b7cf0e76bde44496b4d0794054e6ea60f388682463132f931a7%7D%20%5Cquad%20G_y%5Cin%5Ctextrm%7BGF%7D%28%282%5E%7B15%7D%29%5E%7B17%7D%29%20%5Cend%7Baligned%7D")

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

    <img src="http://latex.codecogs.com/svg.latex?n%3D%5Ctextrm%7B0x1026dd85081b82314691ced9bbec30547840e4bf72d8b5e0d258442bbcd31%7D%20%5Cquad%20n%5Cin%5Cnolinebreak%5Cmathbb%7BZ%7D")

## 3. 消息哈希算法

设长度为 ![l-inlined] 的消息为：

    <img src="http://latex.codecogs.com/svg.latex?M%3Dm_0m_1%20%5Cldots%20m_%7Bl-1%7D%20%5Cquad%20%5Cquad%20m_i%5Cin%5B0%2C%20256%29")

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

    <img src="http://latex.codecogs.com/svg.latex?%5Ctextrm%7BSHA%7D_1%28M%29%3DS_0%7C%7CS_1%7C%7CS_2%7C%7CS_3%7C%7CS_4%20%5Cquad%20%5Cquad%20S_i%5Cin%5B0%2C%202%5E%7B32%7D%29")

其中 ![](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签名时消息的哈希：

    <img src="http://latex.codecogs.com/svg.latex?h%3D%28%5Csum_%7Bi%3D0%7D%5E%7B4%7DS_i%20%5Ccdot%202%5E%7B32i%7D%29+%5Ctextrm%7B0x1bd10xb4e33c7c0ffd8d43%7D%20%5Ccdot%202%5E%7B32*5%7D")

## 4. ECC签名算法

设私钥为 ![k-inlined]，公钥为 ![P-inlined]，即：

    <img src="http://latex.codecogs.com/svg.latex?P%3Dk%20%5Ccdot%20G")

消息哈希为 ![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个字符输出。


code:
# How to build?

[中文版](how-to-build.zh-CN.md)

## 1. Windows

### 1.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.

### 1.2 Build

1. Open this project in __Visual Studio__.

2. Select `Release` configuration.

3. Select __Build > Build Solution__.

You will see executable file in `bin/` directory.

## 2. Linux/macOS

### 2.1 Prerequisites

1. Please make sure you have following libraries:

   ```
   openssl
   mpir
   ```

   __If you use Ubuntu, you can install `openssl` and `mpir` via following commands:__

   ```bash
   # install openssl
   $ sudo apt-get install libssl-dev

   # install mpir
   $ wget http://mpir.org/mpir-3.0.0.tar.bz2
   $ tar -jxvpf ./mpir-3.0.0.tar.bz2
   $ cd mpir-3.0.0
   $ sudo apt-get install yasm      # yasm is required
   $ sudo apt-get install m4        # m4 is required
   $ ./configure --enable-cxx
   $ make
   $ make check
   $ sudo make install
   $ sudo ldconfig
   ```

   __If you use macOS, you can install `openssl` and `mpir` via following commands:__

   ```bash
   $ brew install openssl
   $ brew install mpir
   ```

### 2.2 Build

```bash
$ git clone https://github.com/DoubleLabyrinth/winrar-keygen.git
$ cd winrar-keygen
$ make keygen
```

Then you will see executable file in `bin/` directory.


code:
# 如何编译？

## 1. Windows

### 1.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
   ```

### 1.2 编译

1. 在 __Visual Studio__ 中打开这个项目。

2. 选择 `Release` 配置。

3. 选择 __生成 > 生成解决方案__。

之后你会在 `bin/` 文件夹下看到可执行文件。

## 2. Linux/macOS

### 2.1 前提条件

1. 请确保你有下面几个库:

   ```
   openssl
   mpir
   ```

   __如果你使用Ubuntu，你可以通过下面的命令安装 `openssl` 和 `mpir`：__

   ```bash
   # install openssl
   $ sudo apt-get install libssl-dev

   # install mpir
   $ wget http://mpir.org/mpir-3.0.0.tar.bz2
   $ tar -jxvpf ./mpir-3.0.0.tar.bz2
   $ cd mpir-3.0.0
   $ sudo apt-get install yasm      # yasm is required
   $ sudo apt-get install m4        # m4 is required
   $ ./configure --enable-cxx
   $ make
   $ make check
   $ sudo make install
   $ sudo ldconfig
   ```

   __如果你使用macOS，你可以通过下面的命令安装 `openssl` 和 `mpir`：__

   ```bash
   $ brew install openssl
   $ brew install mpir
   ```

### 2.2 编译

```bash
$ git clone https://github.com/DoubleLabyrinth/winrar-keygen.git
$ cd winrar-keygen
$ make keygen
```

之后你会在 `bin/` 文件夹下看到可执行文件。


code:
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


code:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <VCProjectVersion>16.0</VCProjectVersion>
    <ProjectGuid>{2443AA55-9534-4451-9BCC-48AC0982A0CC}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <RootNamespace>winrarkeygen</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
    <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
    <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
    <IntDir>$(SolutionDir)obj\$(Platform)-$(Configuration)\</IntDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
    <IntDir>$(SolutionDir)obj\$(Platform)-$(Configuration)\</IntDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
    <IntDir>$(SolutionDir)obj\$(Platform)-$(Configuration)\</IntDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
    <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
    <IntDir>$(SolutionDir)obj\$(Platform)-$(Configuration)\</IntDir>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpp17</LanguageStandard>
      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpp17</LanguageStandard>
      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpp17</LanguageStandard>
      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpp17</LanguageStandard>
      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="_tmain.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="BigInteger.hpp" />
    <ClInclude Include="Hasher.hpp" />
    <ClInclude Include="EllipticCurveGF2m.hpp" />
    <ClInclude Include="GaloisField.hpp" />
    <ClInclude Include="HasherSha1Traits.hpp" />
    <ClInclude Include="WinRarKeygen.hpp" />
    <ClInclude Include="HasherCrc32Traits.hpp" />
    <ClInclude Include="WinRarConfig.hpp" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>


code:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="源文件">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="头文件">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
    </Filter>
    <Filter Include="资源文件">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="_tmain.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="GaloisField.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="EllipticCurveGF2m.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Hasher.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="HasherCrc32Traits.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="HasherSha1Traits.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="BigInteger.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="WinRarKeygen.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="WinRarConfig.hpp">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
</Project>


code:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ShowAllFiles>true</ShowAllFiles>
  </PropertyGroup>
</Project>


code:
/build/
/install/
/release/
/sources/
/libreboot.conf
.version
.revision
.tarfiles
.epoch
push
*.vim
/TODO/
/docs/version
/bucts/
/coreboot/
/crossgcc/
/flashrom/
/grub/
/memtest86plus/
/seabios/
/bin/
/resources/utilities/ich9deblob/*.rom
/resources/utilities/ich9deblob/*.bin
/resources/utilities/ich9deblob/ich9deblob
/resources/utilities/ich9deblob/ich9gen
/resources/utilities/ich9deblob/demefactory
/resources/utilities/ich9deblob/obj/*.o
/resources/utilities/ich9deblob/obj/*/*.o
/resources/utilities/ich9deblob/mkdescriptor*.[ch]
/resources/utilities/ich9deblob/mkgbe*.[ch]
/resources/utilities/grub-assemble/grub_*.elf
/mkgbe.[ch]
/*.bin
/resources/utilities/i945-pwm/i945-pwm
/push
/ChangeLog
/NEWS
/version
/versiondate
/gm45macaddress
tocheck*
*.html
!www/template.html
/www/temp.md
/www/news/index.md

repo_name: tiveket/libreboot

path: .gitignore

license: mit


code:
Paper Build System
==================

Entry Point
-----------

The entry point for using the paper build system is the main script in the root
directory, named after the build system (paper, libreboot, etc).
Running the main script with no argument will show its general usage.

Configuration
-------------

The paper build system can be configured with a script named after the build
system (paper, libreboot, etc) with a ".conf" suffix. It is automatically loaded
by the build system when running the main script.

It contains environment variables assigned to the desired values. The list of
environment variables is shown in the main script's general usage.

Project and Tool Targets
------------------------

The build system works around the concepts of projects and tools, that define
specific components that can be used to produce either:
* sources
* systems
* images
* tools

Various actions are available for each project and tool targets, many of which
are shown in the main script's general usage. Each project and tool may provide
a usage action that allows to see the specific usage for it. Actions are
executed recursively when no targets are specified.

Each project and tool target has its own directory (either in projects or tools)
that contain a script named after the target and possible a helper script, named
after the script with a "-helper" suffix. The helper script is automatically
included by the build system. Functions in helper scripts are usually prefixed
with the name of the target, where "-" symbols are replaced with "_" symbols.

Each project and tool target's actions are functions defined in the target's
specific script, with names matching the target's actions.

Meta-Targets
------------

Meta targets are project and tool targets that apply the requested action to
individual targets, allowing to execute an action to many targets at once.
For instance, a meta-target named after the build system with a "-all" suffix
would call other meta-targets, prefixed with "-images", "-tools", etc that would
then perform the requested action to all underlying targets.

Projects Actions
----------------

Various generic actions allow preparing projects through a series of steps:
* downloading, extracting or updating the project's sources
* building the project to a build directory
* installing the project to an install directory
* releasing the project to a release directory
* cleaning the build, install and release directories

Actions can be checked by a matching project-specific function, named after the
function to check with a "_check" suffix, to determine whether it is necessary
to run them again to follow the steps. An environment variable can force actions
to be executed, by specifying a space-separated list of projects:
PROJECTS_FORCE.

Projects Configuration and Patches
----------------------------------

Configuration for each project is stored in each project's own directory.
Targets for each project are defined with a "targets" file in each directory
of the "configs" directory. Targets are read recursively, following
sub-directory names for project targets.

Each project's configuration directory can be used to hold target-specific
information and configuration.

An "install" file in each sub-directory indicated which files to grab from the
build files and where to install them in the install directory.

Projects Sources
----------------

Each project can either download specific sources or use another project's
sources, possibly providing its own revision and patches.

Sources are downloaded with the "download" action or can be extracted from
released sources (after placing the sources in the sources directory) with the
"extract" action.

Projects may also keep their sources in a "sources" directory in their
project-specific directory.

Projects Build
--------------

Each project is built to a build directory, named after the project, with the
list of targets separated by a "-" symbol.

An environment variable allows controlling the number of tasks to run at the
same time: TASKS.

Projects Install
----------------

Projects are installed from "install" files in the project directory, that
copies the selected built files to the install directory, named after the
project, with the list of targets separated by a "-" symbol. These install files
are read recursively, following sub-directory names for project targets.

Additional files to install can be specified in the "install" directory and
described in an "install" file. These install files are read recursively,
following sub-directory names for project targets.

Projects Release
----------------

Projects are released to a release directory, named after the project, with the
list of targets separated by a "-" symbol. Each project's install files are
packed into a tarball to the corresponding release directory. A checksum and a
GPG detached signature (if the RELEASE_KEY environment variable is set) are also
generated.

Tarballs are generated reproducibly, from a list of files stored in the
".tarfiles" file. They may also contain the ".epoch", git ".revision" and
".version" files.

Tools Actions
-------------

Tools are used for maintaining the build system, for performing routine tasks
that can be automated. They may have specific actions and not implement any of
the generic actions.

Actions can be checked by a matching tool-specific function, named after the
function to check with a "_check" suffix, to determine whether it is necessary
to run them again to follow the steps. An environment variable can force actions
to be executed, by specifying a space-separated list of tasks: TASKS_FORCE.

Tools Sources
-------------

Tools may keep their sources in a "sources" directory in their tool-specific
directory. These sources may be updated with the "update" action.


code:
Libreboot project

Libreboot documentation is under docs/
The website is https://libreboot.org/
License can be found in COPYING and through parts of the source tree.

Libreboot is a free BIOS or UEFI replacement (free as in freedom); libre boot
firmware that initializes the hardware and starts a bootloader for your
operating system. It's also an open source BIOS, but open source fails to
promote freedom; please call libreboot free software.

Why use libreboot?

Many people use non-free boot firmware, even if they use GNU+Linux. Non-free
BIOS/UEFI firmware often contains backdoors, can be slow and have severe bugs,
where you are left helpless at the mercy of the developers; you have no freedom
over your computing. By contrast, libreboot is building a world where
everyone can use, study, adapt and share software, with true control and
ownership over their technology. In other words, you should use Libreboot for
your freedom's sake!

Libreboot is faster, more secure and more reliable than most non-free firmware,
and can provide many advanced features (such as encrypted /boot/, GPG signature
checking before booting your kernel, ability to load an OS from the flash chip,
and more).

Libreboot's main upstream providers are coreboot (which we deblob, for hardware
initialization), depthcharge (bootloader, and default libreboot payload on ARM),
and GRUB (bootloader, and default libreboot payload on x86). We also
integrate flashrom (for installing libreboot), and several of our own utilities,
scripts and configuration files. All of this is integrated into a single,
coherent package that is easy to use. We add our own patches to the various
upstreams used, and where feasible try to merge upstream as much as possible.

Libreboot provides a fully automated build system and installation process, with
documentation written for non-technical users, in an attempt to make the
software as easy to use as possible. ROM images are provided, along with
utilities, all built from the publicly distributed source code.

This README is licensed under Creative Commons Zero 1.0:
https://creativecommons.org/publicdomain/zero/1.0/

path: README


code:
Libreboot 20160907

For existing boards, there are no new board specific changes.

This release adds one new mainboard to libreboot:
* Intel D945GCLF desktop motherboard (thanks to Arthur Heymans)

Other bugfixes:
* Various improvements to the documentation
* re-added "unset superusers" to the grub.cfg, which was needed for some users
  depending on the distros that they used

Libreboot 20160902

This is a bugfix release, based on 20160818. It contains no new board changes.
The previous 20160818 release had build errors in the _src archive, and the
_util archive was only source code.

Changes compared to 20160818:
* Fixed bug where ./build module coreboot always returned non-zero status
* Fixed missing symlink of crossgcc when building from _src (thanks Arthur
Heymans)
* Fixed building with the depthcharge payload (ASUS C201)
* Proper ChangeLog now, instead of pasted git log
* Util archive is now binaries again (source code is in the _src archive)
* Documentation is now in HTML format

Libreboot 20160818

NEW BOARDS ADDED:
* ASUS Chromebook C201 (ARM laptop) (thanks to Paul Kocialkowski)
* Gigabyte GA-G41M-ES2L motherboard (desktop) (thanks to Damien Zammit)
* Intel D510MO motherboard (desktop) (thanks to Damien Zammit)
* ASUS KCMA-D8 motherboard (desktop) (thanks to Timothy Pearson)
* ASUS KFSN4-DRE motherboard (server) (thanks to Timothy Pearson)
* ASUS KGPE-D16 motherboard (server) (thanks to Timothy Pearson)

For boards previously supported, many fixes from upstream have been merged.

Other changes (compared to libreboot 20150518):
(this is a summary. For more detailed change list, refer to the git log)

256MiB VRAM allocated on GM45 (X200, T400, T500, R400) instead of 32MiB.
This is an improvement over both Lenovo BIOS and Libreboot 20150518, allowing
video decoding at 1080p to be smoother. (thanks Arthur Heymans)
To clarify, GM45 video performance in libreboot 20160818 is better than on
the original BIOS and the previous libreboot release.

64MiB VRAM on i945 (X60, T60, MacBook2,1) now supported in coreboot-libre, and
used by default (in the previous release, it was 8MiB allocated). Thanks to
Arthur Heymans.

Higher battery life on GM45 (X200, T400, T500, R400) due to higher cstates now
being supported (thanks Arthur Heymans). C4 power states also supported.

Text mode on GM45 (X200, T400, T500, R400) now works, making it possible to
use MemTest86+ comfortably. (thanks to Nick High from coreboot)

Dual channel LVDS displays on GM45 (T400, T500) are now automatically
detected in coreboot-libre. (thanks Vladimir Serbinenko from coreboot)

Partial fix in coreboot-libre for GRUB display on GM45, for dual channel
LVDS higher resolution LCD panels (T400, T500). (thanks Arthur Heymans)

Massively improved GRUB configuration, making it easier to boot more
encrypted systems automatically, and generally a more useful menu for booting
the system (thanks go to Klemens Nanni of the autoboot project).
Libreboot now uses the grub.cfg provided by the installed GNU+Linux distribution
automatically, if present, switching to that configuration. This is done across
many partitions, where libreboot actively searches for a configuration file
(also on LVM volumes and encrypted volumes). This should make libreboot more
easy to use for non-technical users, without having to modify the GRUB
configuration used in libreboot.

Utilities archives is now source only. You will need to compile the packages
in there (build scripts included, and a script for installing build
dependencies. (binary utility archives are planned again in the next
release, when the new build system is merged)

SeaGRUB is now the default payload on all x86 boards. (SeaBIOS configured to
load a compressed GRUB payload from CBFS immediately, without providing an
interface in SeaBIOS. This way, GRUB is still used but now BIOS services are
available, so you get the best of both worlds). Thanks go to Timothy Pearson
of coreboot for this idea.

crossgcc is now downloaded and built as a separate module to coreboot-libre,
with a universal revision used to build all boards.

Individual boards now have their own coreboot revision and patches, independently
of each other board. This makes maintenance easier.

Updated all utilities, and modules (coreboot, GRUB, etc) to newer versions,
with various bugfixes and improvements upstream.

RTC century byte issue now fixed on GM45 in coreboot-libre, so the date
should now be correctly displayed when running the latest linux kernel, instead
of seeing 1970-01-01 when you boot (thanks to Alexander Couzens from coreboot)

Build system now uses multiple CPU cores when building, speeding up building
for some people. Manually specifying how many cores are needed is also possible,
for those using the build system in a chroot environment. (thanks go to
Timothy Pearson from coreboot)

In the build system (git repository), https:// is now used when cloning coreboot.
http:// is used as a fallback for GRUB, if git:// fails.

New payload, the depthcharge bootloader (free bootloader maintained by Google)
for use on the ASUS Chromebook C201. (thanks go to Paul Kocialkowski)

Various fixes to the ich9gen utility (e.g. flash component density is now
set correctly in the descriptor, gbe-less descriptors now supported)

path: RELEASE


code:
---
title: How to install FreeBSD on a libreboot system
...

This section relates to preparing, booting and installing FreeBSD on
your libreboot system, using nothing more than a USB flash drive (and
*dd*). They've only been tested on a Lenovo ThinkPad x200.

It is expected that you use text mode in libreboot (txtmode images), for
the early boot process in FreeBSD. **Booting the installer results in a
red flickering text display, and doesn't boot.**

Thanks go to ioxcide in [this Reddit
post](https://www.reddit.com/r/BSD/comments/53jt70/libreboot_and_bsds/)
for the initial instructions.

TODO: test FreeBSD more extensively, and make sure it works (and fix it
if it does not). Instructions are provided here, to boot and install
FreeBSD but we're not sure whether it is currently fully compatible
with libreboot.

-   [Prepare the USB drive (in FreeBSD)](#prepare)
-   [Installing FreeBSD without full disk encryption](#noencryption)
-   [Installing FreeBSD with full disk encryption](#encryption)
-   [Booting](#booting)
-   [Configuring Grub](#configuring_grub)
-   [Troubleshooting](#troubleshooting)

**This section is only for the GRUB payload. For depthcharge (used on
CrOS devices in libreboot), instructions have yet to be written in the
libreboot documentation.**

freebsd.img is the installation image for FreeBSD. Adapt the filename
accordingly, for whatever FreeBSD version you use.

Prepare the USB drive (in FreeBSD)
----------------------------------

[This page](https://www.freebsd.org/doc/handbook/bsdinstall-pre.html) on
the FreeBSD website shows how to create a bootable USB drive for
installing FreeBSD. Use the *dd* on that page.

Prepare the USB drive (in NetBSD)
---------------------------------

[This
page](https://wiki.netbsd.org/tutorials/how_to_install_netbsd_from_an_usb_memory_stick/)
on the NetBSD website shows how to create a NetBSD bootable USB drive
from within NetBSD itself. You should use the *dd* method documented
there; you can use this with any ISO, including FreeBSD.

Prepare the USB drive (in LibertyBSD or OpenBSD)
------------------------------------------------

If you downloaded your ISO on a LibertyBSD or OpenBSD system, here is
how to create the bootable FreeBSD USB drive:

Connect the USB drive. Check dmesg:

    $ dmesg | tail

Check to confirm which drive it is, for example, if you think its sd3:

    $ disklabel sd3

Check that it wasn't automatically mounted. If it was, unmount it. For
example:

    $ doas umount /dev/sd3i

dmesg told you what device it is. Overwrite the drive, writing the
FreeBSD installer to it with dd. For example:

    $ doas dd if=freebsd.img of=/dev/rsdXc bs=1M; sync

You should now be able to boot the installer from your USB drive.
Continue reading, for information about how to do that.

Prepare the USB drive (in GNU+Linux)
------------------------------------

If you downloaded your ISO on a GNU+Linux system, here is how to create
the bootable FreeBSD USB drive:

Connect the USB drive. Check dmesg:

    $ dmesg
Check lsblk to confirm which drive it is:

    $ lsblk

Check that it wasn't automatically mounted. If it was, unmount it. For
example:

    $ sudo umount /dev/sdX\*
    # umount /dev/sdX\*

dmesg told you what device it is. Overwrite the drive, writing your
distro ISO to it with dd. For example:

    $ sudo dd if=freebsd.img of=/dev/sdX bs=8M; sync
    # dd if=freebsd.img of=/dev/sdX bs=8M; sync

You should now be able to boot the installer from your USB drive.
Continue reading, for information about how to do that.

Installing FreeBSD without full disk encryption
-----------------------------------------------

Press C in GRUB to access the command line:

    grub> kfreebsd (usb0,gpt3)/boot/kernel/kernel
    grub> set FreeBSD.vfs.mountfrom=ufs:/dev/da1p3\
    grub> boot

It will start booting into the FreeBSD installer. Follow the normal
process for installing FreeBSD.

Installing FreeBSD with full disk encryption
--------------------------------------------

TODO

Booting
-------

TODO

Configuring Grub
----------------

TODO

Troubleshooting
===============

Most of these issues occur when using libreboot with coreboot's 'text
mode' instead of the coreboot framebuffer. This mode is useful for
booting payloads like memtest86+ which expect text-mode, but for FreeBSD
it can be problematic when they are trying to switch to a framebuffer
because it doesn't exist.

In most cases, you should use the vesafb ROM images. Example filename:
libreboot\_ukdvorak\_vesafb.rom.

won't boot\...something about file not found
---------------------------------------------

Your device names (i.e. usb0, usb1, sd0, sd1, wd0, ahci0, hd0, etc) and
numbers may differ. Use TAB completion.

Copyright © 2016 Leah Rowe <info@minifree.org>\
Copyright © 2016 Scott Bonds <scott@ggr.com>\
This page is available under the [CC BY SA 4.0](../cc-by-sa-4.0.txt)


code:
---
title: BSD projects
...

This section relates to dealing with BSD projects: preparing bootable
USB drives, changing the default GRUB menu and so on.

**This section is only for the \*GRUB\* payload. For depthcharge,
instructions have yet to be written.**

-   [How to install NetBSD on a libreboot system](netbsd.md)
-   [How to install LibertyBSD or OpenBSD on a libreboot
    system](openbsd.md)

-   [How to install FreeBSD on a libreboot system](freebsd.md)

Copyright © 2016 Scott Bonds <scott@ggr.com>\
This page is available under the [CC BY SA 4.0](../cc-by-sa-4.0.txt)


code:
---
title: How to install NetBSD on a libreboot system
...

This section relates to preparing, booting and installing NetBSD on your
libreboot system, using nothing more than a USB flash drive (and *dd*).
They've only been tested on a librebooted ThinkPad X60.

It is expected that you use text mode in libreboot (txtmode images), for
the early boot process in NetBSD. **Suspend/hibernate is broken,
according to at least 1 user.**

Thanks go to ioxcide in [this Reddit
post](https://www.reddit.com/r/BSD/comments/53jt70/libreboot_and_bsds/)
for the initial instructions.

-   [Prepare the USB drive (in NetBSD)](#prepare)
-   [Installing NetBSD without full disk encryption](#noencryption)
-   [Installing NetBSD with full disk encryption](#encryption)
-   [Booting](#booting)
-   [Configuring Grub](#configuring_grub)
-   [Troubleshooting](#troubleshooting)

**This section is only for the GRUB payload. For depthcharge (used on
CrOS devices in libreboot), instructions have yet to be written in the
libreboot documentation.**

netbsd.iso is the installation image for NetBSD. Adapt the filename
accordingly, for your version of NetBSD.

Prepare the USB drive (in NetBSD)
---------------------------------

[This
page](https://wiki.netbsd.org/tutorials/how_to_install_netbsd_from_an_usb_memory_stick/)
on the NetBSD website shows how to create a NetBSD bootable USB drive
from within NetBSD itself. You should use the *dd* method documented
there.

Prepare the USB drive (in FreeBSD)
----------------------------------

[This page](https://www.freebsd.org/doc/handbook/bsdinstall-pre.html) on
the FreeBSD website shows how to create a bootable USB drive for
installing FreeBSD. Use the *dd* on that page. You can also use the same
instructions with a NetBSD ISO image.

Prepare the USB drive (in LibertyBSD or NetBSD)
-----------------------------------------------

If you downloaded your ISO on a LibertyBSD or NetBSD system, here is how
to create the bootable NetBSD USB drive:

Connect the USB drive. Check dmesg:

    $ dmesg | tail

Check to confirm which drive it is, for example, if you think its sd3:

    $ disklabel sd3

Check that it wasn't automatically mounted. If it was, unmount it. For
example:

    $ doas umount /dev/sd3i

dmesg told you what device it is. Overwrite the drive, writing the
NetBSD installer to it with dd. For example:

    $ doas netbsd.iso of=/dev/rsdXc bs=1M; sync

You should now be able to boot the installer from your USB drive.
Continue reading, for information about how to do that.

Prepare the USB drive (in GNU+Linux)
------------------------------------

If you downloaded your ISO on a GNU+Linux system, here is how to create
the bootable NetBSD USB drive:

Connect the USB drive. Check dmesg:

    $ dmesg
Check lsblk to confirm which drive it is:

    $ lsblk

Check that it wasn't automatically mounted. If it was, unmount it. For
example:

    $ sudo umount /dev/sdX\*
    # umount /dev/sdX\*

dmesg told you what device it is. Overwrite the drive, writing your
distro ISO to it with dd. For example:

    $ sudo dd if=install60.fs of=/dev/sdX bs=8M; sync
    # dd if=netbsd.iso of=/dev/sdX bs=8M; sync

You should now be able to boot the installer from your USB drive.
Continue reading, for information about how to do that.

Installing NetBSD without full disk encryption
----------------------------------------------

You might have to use an external USB keyboard during the installation.
Press C to access the GRUB terminal.

    grub> knetbsd -r sd0a (usb0,netbsd1)/netbsd
    grub> boot

It will start booting into the NetBSD installer. Follow the normal
process for installing NetBSD.

Installing NetBSD with full disk encryption
-------------------------------------------

TODO

Booting
-------

Press C in GRUB to access the command line:

    grub> knetbsd -r wd0a (ahci0,netbsd1)/netbsd
    grub> boot

NetBSD will start booting. Yay!

Configuring Grub
----------------

If you don't want to drop to the GRUB command line and type in a
command to boot NetBSD every time, you can create a GRUB configuration
that's aware of your NetBSD installation and that will automatically be
used by libreboot.

On your NetBSD root partition, create the **/grub** directory and add
the file **libreboot\_grub.cfg** to it. Inside the
**libreboot\_grub.cfg** add these lines:

**default=0 timeout=3 menuentry "NetBSD" {\
    knetbsd -r wd0a (ahci0,netbsd1)/netbsd\
}\
**

The next time you boot, you'll see the old Grub menu for a few seconds,
then you'll see the a new menu with only NetBSD on the list. After 3
seconds NetBSD will boot, or you can hit enter to boot.

Troubleshooting
===============

Most of these issues occur when using libreboot with coreboot's 'text
mode' instead of the coreboot framebuffer. This mode is useful for
booting payloads like memtest86+ which expect text-mode, but for NetBSD
it can be problematic when they are trying to switch to a framebuffer
because it doesn't exist.

In most cases, you should use the vesafb ROM images. Example filename:
libreboot\_ukdvorak\_vesafb.rom.

won't boot\...something about file not found
---------------------------------------------

Your device names (i.e. usb0, usb1, sd0, sd1, wd0, ahci0, hd0, etc) and
numbers may differ. Use TAB completion.

Copyright © 2016 Leah Rowe <info@minifree.org>\
Copyright © 2016 Scott Bonds <scott@ggr.com>\
This page is available under the [CC BY SA 4.0](../cc-by-sa-4.0.txt)


code:
---
title: How to install LibertyBSD or OpenBSD on a libreboot system
...

NOTE: This guide was written for OpenBSD by the person who contributed
it, but the libreboot project recommends LibertyBSD. LibertyBSD is a
version of OpenBSD without proprietary software in the repositories
(OpenBSD distributes firmware blobs for devices inside its kernel). Go
to the [LibertyBSD website](http://libertybsd.net/) -- TODO: test on
LibertyBSD and prioritise that in this guide.

This section relates to preparing, booting and installing OpenBSD on
your libreboot system, using nothing more than a USB flash drive (and
*dd*). They've only been tested on a Lenovo ThinkPad x200.

-   [Prepare the USB drive (in OpenBSD)](#prepare)
-   [Installing OpenBSD without full disk encryption](#noencryption)
-   [Installing OpenBSD with full disk encryption](#encryption)
-   [Booting](#booting)
-   [Configuring Grub](#configuring_grub)
-   [Troubleshooting](#troubleshooting)

**This section is only for the GRUB payload. For depthcharge (used on
CrOS devices in libreboot), instructions have yet to be written in the
libreboot documentation.**

install60.fs is the installation image for OpenBSD 6.0. Adapt the
filename accordingly, for a different OpenBSD version or LibertyBSD.

Prepare the USB drive (in LibertyBSD or OpenBSD)
------------------------------------------------

If you downloaded your ISO on a LibertyBSD or OpenBSD system, here is
how to create the bootable LibertyBSD/OpenBSD USB drive:

Connect the USB drive. Check dmesg:

    $ dmesg | tail

Check to confirm which drive it is, for example, if you think its sd3:

    $ disklabel sd3

Check that it wasn't automatically mounted. If it was, unmount it. For
example:

    $ doas umount /dev/sd3i

dmesg told you what device it is. Overwrite the drive, writing the
OpenBSD installer to it with dd. For example:

    $ doas dd if=install60.fs of=/dev/rsdXc bs=1M; sync

You should now be able to boot the installer from your USB drive.
Continue reading, for information about how to do that.

Prepare the USB drive (in NetBSD)
---------------------------------

[This
page](https://wiki.netbsd.org/tutorials/how_to_install_netbsd_from_an_usb_memory_stick/)
on the NetBSD website shows how to create a NetBSD bootable USB drive
from within NetBSD itself. You should use the *dd* method documented
there. This will also work with the OpenBSD image.

Prepare the USB drive (in FreeBSD)
----------------------------------

[This page](https://www.freebsd.org/doc/handbook/bsdinstall-pre.md) on
the FreeBSD website shows how to create a bootable USB drive for
installing FreeBSD. Use the *dd* on that page. You can also use the same
instructions with a OpenBSD ISO image.

Prepare the USB drive (in GNU+Linux)
------------------------------------

If you downloaded your ISO on a GNU+Linux system, here is how to create
the bootable OpenBSD USB drive:

Connect the USB drive. Check dmesg:

    $ dmesg
Check lsblk to confirm which drive it is:

    $ lsblk

Check that it wasn't automatically mounted. If it was, unmount it. For
example:

    $ sudo umount /dev/sdX\*
    # umount /dev/sdX\*

dmesg told you what device it is. Overwrite the drive, writing your
distro ISO to it with dd. For example:

    $ sudo dd if=install60.fs of=/dev/sdX bs=8M; sync
    # dd if=install60.fs of=/dev/sdX bs=8M; sync

You should now be able to boot the installer from your USB drive.
Continue reading, for information about how to do that.

Installing OpenBSD without full disk encryption
-----------------------------------------------

Press C in GRUB to access the command line:

    grub> kopenbsd (usb0,openbsd1)/6.0/amd64/bsd.rd
    grub> boot

It will start booting into the OpenBSD installer. Follow the normal
process for installing OpenBSD.

Installing OpenBSD with full disk encryption
--------------------------------------------

Not working. You can modify the above procedure (installation w/o
encryption) to install OpenBSD using full disk encryption, and it
appears to work, except that its not yet clear how to actually *boot* an
OpenBSD+FDE installation using libreboot+Grub2. If you get it working,
please let us know.

If booting in text mode (framebuffer mode might also work), it might be
possible to chainload the OpenBSD or LibertyBSD bootloader from the MBR
section on the internal storage device. This way, it would be possible
to boot with an encrypted OpenBSD or LibertyBSD installation. Please let
us know (contact details are on the libreboot homepage) if you get it
working this way.

Alternatively, it would be good to port OpenBSD either natively as a
coreboot payload, or port it to libpayload (payload library in coreboot;
it has a basic C library and a few functions for certain operations e.g.
text/bitmap). **This would be ideal, because then it would be possible
to boot a truly fully encrypted OpenBSD or LibertyBSD installation, by
putting everything in the flash chip.**

Alternatively, modifying GRUB to support booting fully encrypted OpenBSD
installations would be possible, but probably not feasible; it's an
alien codebase to the OpenBSD project, not tightly integrated and the
OpenBSD bootloader already works.

Booting
-------

Press C in GRUB to access the command line:

    grub> kopenbsd -r sd0a (ahci0,openbsd1)/bsd
    grub> boot

OpenBSD will start booting. Yay!

Configuring Grub
----------------

If you don't want to drop to the GRUB command line and type in a
command to boot OpenBSD every time, you can create a GRUB configuration
that's aware of your OpenBSD installation and that will automatically
be used by libreboot.

On your OpenBSD root partition, create the **/grub** directory and add
the file **libreboot\_grub.cfg** to it. Inside the
**libreboot\_grub.cfg** add these lines:

**default=0 timeout=3 menuentry "OpenBSD" {\
    kopenbsd -r sd0a (ahci0,openbsd1)/bsd\
}\
**

The next time you boot, you'll see the old Grub menu for a few seconds,
then you'll see the a new menu with only OpenBSD on the list. After 3
seconds OpenBSD will boot, or you can hit enter to boot.

Troubleshooting
===============

Most of these issues occur when using libreboot with coreboot's 'text
mode' instead of the coreboot framebuffer. This mode is useful for
booting payloads like memtest86+ which expect text-mode, but for OpenBSD
it can be problematic when they are trying to switch to a framebuffer
because it doesn't exist.

In most cases, you should use the vesafb ROM images. Example filename:
libreboot\_ukdvorak\_vesafb.rom.

won't boot\...something about file not found
---------------------------------------------

Your device names (i.e. usb0, usb1, sd0, sd1, wd0, ahci0, hd0, etc) and
numbers may differ. Use TAB completion.

Copyright © 2016 Scott Bonds <scott@ggr.com>\
Copyright © 2016 Leah Rowe <info@minifree.org>\
This page is available under the [CC BY SA 4.0](../cc-by-sa-4.0.txt)