implement crypto.cc with OpenSSL + fix config loading
I considered reversing the original `vlong` implementation but OpenSSL is just simpler, more secure, and most importantly, is already there. I also made it so the key is now stored in a PEM file (`tibia.pem`) so it can be easily swapped without re-compiling. This was the last piece to build and run a working executable, except that we now need to implement a query manager for the server to communicate with. I was able to fix a small problem with loading the config before hitting the problem with the query manager, which was expected. The next task should be getting a query manager up and running before starting phase two of upgrading and fixing the server itself.
This commit is contained in:
parent
e782274ade
commit
e65dc561ac
6
Makefile
6
Makefile
@ -3,8 +3,8 @@ BUILDDIR = build
|
|||||||
OUTPUTEXE = game
|
OUTPUTEXE = game
|
||||||
|
|
||||||
CC = g++
|
CC = g++
|
||||||
CFLAGS = -m64 -fno-strict-aliasing -pedantic -Wall -Wextra -Wno-unused-parameter -Wno-format-truncation -std=c++11 -DOS_LINUX=1 -DARCH_X64=1
|
CFLAGS = -m64 -fno-strict-aliasing -pedantic -Wall -Wextra -Wno-unused-parameter -Wno-format-truncation -std=c++11 -pthread -DOS_LINUX=1 -DARCH_X64=1
|
||||||
LFLAGS = -Wl,-t
|
LFLAGS = -Wl,-t -lcrypto
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
ifneq ($(DEBUG), 0)
|
ifneq ($(DEBUG), 0)
|
||||||
@ -16,7 +16,7 @@ endif
|
|||||||
HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/communication.hh $(SRCDIR)/config.hh $(SRCDIR)/connections.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/crypto.hh $(SRCDIR)/enums.hh $(SRCDIR)/houses.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/moveuse.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/query.hh $(SRCDIR)/reader.hh $(SRCDIR)/script.hh $(SRCDIR)/threads.hh $(SRCDIR)/writer.hh
|
HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/communication.hh $(SRCDIR)/config.hh $(SRCDIR)/connections.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/crypto.hh $(SRCDIR)/enums.hh $(SRCDIR)/houses.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/moveuse.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/query.hh $(SRCDIR)/reader.hh $(SRCDIR)/script.hh $(SRCDIR)/threads.hh $(SRCDIR)/writer.hh
|
||||||
|
|
||||||
$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/communication.obj $(BUILDDIR)/config.obj $(BUILDDIR)/connections.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crnonpl.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/crypto.obj $(BUILDDIR)/houses.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/query.obj $(BUILDDIR)/reader.obj $(BUILDDIR)/receiving.obj $(BUILDDIR)/script.obj $(BUILDDIR)/sending.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/threads.obj $(BUILDDIR)/time.obj $(BUILDDIR)/utils.obj $(BUILDDIR)/writer.obj
|
$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/communication.obj $(BUILDDIR)/config.obj $(BUILDDIR)/connections.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crnonpl.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/crypto.obj $(BUILDDIR)/houses.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/query.obj $(BUILDDIR)/reader.obj $(BUILDDIR)/receiving.obj $(BUILDDIR)/script.obj $(BUILDDIR)/sending.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/threads.obj $(BUILDDIR)/time.obj $(BUILDDIR)/utils.obj $(BUILDDIR)/writer.obj
|
||||||
$(CC) $(CFLAGS) $(LFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)
|
||||||
|
|
||||||
$(BUILDDIR)/communication.obj: $(SRCDIR)/communication.cc $(HEADERS)
|
$(BUILDDIR)/communication.obj: $(SRCDIR)/communication.cc $(HEADERS)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
|
|||||||
3493
reference/game.c
3493
reference/game.c
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
|||||||
|
|
||||||
struct TDatabasePoolConnection {
|
|
||||||
TDatabaseConnectionPool *DatabaseConnectionPool;
|
|
||||||
TDatabaseConnection *DatabaseConnection;
|
|
||||||
bool TransactionRunning;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TDatabaseConnectionPool {
|
|
||||||
int NumberOfConnections;
|
|
||||||
struct TDatabaseSettings DatabaseSettings;
|
|
||||||
struct TDatabaseConnection **DatabaseConnection;
|
|
||||||
bool *DatabaseConnectionFree;
|
|
||||||
struct Semaphore FreeDatabaseConnections;
|
|
||||||
struct Semaphore DatabaseConnectionMutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO(fusion): Opaque struct?
|
|
||||||
struct TDatabaseConnection {};
|
|
||||||
|
|
||||||
struct TPreparedQuery {
|
|
||||||
int Number;
|
|
||||||
char *Query;
|
|
||||||
char *DBTypes;
|
|
||||||
char *CTypes;
|
|
||||||
char *Name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TNameLockOrderData {
|
|
||||||
ulong GamemasterID;
|
|
||||||
char GamemasterName[30];
|
|
||||||
char CharacterName[30];
|
|
||||||
bool OldNameVisible;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TNotationOrderData {
|
|
||||||
ulong GamemasterID;
|
|
||||||
char GamemasterName[30];
|
|
||||||
char CharacterName[30];
|
|
||||||
char Comment[200];
|
|
||||||
};
|
|
||||||
@ -23,16 +23,6 @@
|
|||||||
#define MAX_COMMUNICATION_THREADS 1100
|
#define MAX_COMMUNICATION_THREADS 1100
|
||||||
#define COMMUNICATION_THREAD_STACK_SIZE ((int)KB(64))
|
#define COMMUNICATION_THREAD_STACK_SIZE ((int)KB(64))
|
||||||
|
|
||||||
static const char RSA_PRIME_P[] =
|
|
||||||
"1201758001370723323398753778257470257713354828752713123415294815"
|
|
||||||
"0506251412291888866940292054989907714155267326586216043845592229"
|
|
||||||
"084368540020196135619327879";
|
|
||||||
|
|
||||||
static const char RSA_PRIME_Q[] =
|
|
||||||
"1189892136861686835188050824611210139447876026576932541274639840"
|
|
||||||
"5473436969889506919017477758618276066588858607419440134394668095"
|
|
||||||
"105156501566867770737187273";
|
|
||||||
|
|
||||||
static int TERMINALVERSION[3] = {770, 770, 770};
|
static int TERMINALVERSION[3] = {770, 770, 770};
|
||||||
static int TCPSocket;
|
static int TCPSocket;
|
||||||
static ThreadHandle AcceptorThread;
|
static ThreadHandle AcceptorThread;
|
||||||
@ -1533,7 +1523,9 @@ void InitCommunication(void){
|
|||||||
AcceptorThreadPID = 0;
|
AcceptorThreadPID = 0;
|
||||||
ActiveConnections = 0;
|
ActiveConnections = 0;
|
||||||
QueryManagerConnectionPool.init();
|
QueryManagerConnectionPool.init();
|
||||||
PrivateKey.init(RSA_PRIME_P, RSA_PRIME_Q);
|
|
||||||
|
// TODO(fusion): This is arbitrary, should probably be set in the config.
|
||||||
|
PrivateKey.initFromFile("tibia.pem");
|
||||||
|
|
||||||
OpenSocket();
|
OpenSocket();
|
||||||
if(TCPSocket == -1){
|
if(TCPSocket == -1){
|
||||||
|
|||||||
@ -106,6 +106,7 @@ void ReadConfig(void){
|
|||||||
MANAGER_DATABASE.Database[0] = 0;
|
MANAGER_DATABASE.Database[0] = 0;
|
||||||
|
|
||||||
char FileName[4096];
|
char FileName[4096];
|
||||||
|
#if 0
|
||||||
if(const char *Home = getenv("home")){
|
if(const char *Home = getenv("home")){
|
||||||
snprintf(FileName, sizeof(FileName), "%s/.tibia", Home);
|
snprintf(FileName, sizeof(FileName), "%s/.tibia", Home);
|
||||||
}else if(const char *Home = getenv("HOME")){
|
}else if(const char *Home = getenv("HOME")){
|
||||||
@ -113,6 +114,9 @@ void ReadConfig(void){
|
|||||||
}else{
|
}else{
|
||||||
snprintf(FileName, sizeof(FileName), ".tibia");
|
snprintf(FileName, sizeof(FileName), ".tibia");
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
snprintf(FileName, sizeof(FileName), ".tibia");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!FileExists(FileName)){
|
if(!FileExists(FileName)){
|
||||||
throw "cannot find config-file";
|
throw "cannot find config-file";
|
||||||
@ -130,7 +134,7 @@ void ReadConfig(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
char Identifier[MAX_IDENT_LENGTH];
|
char Identifier[MAX_IDENT_LENGTH];
|
||||||
strcpy(Identifier, Script.readIdentifier());
|
strcpy(Identifier, Script.getIdentifier());
|
||||||
Script.readSymbol('=');
|
Script.readSymbol('=');
|
||||||
|
|
||||||
// TODO(fusion): Ughh... Get rid of all `strcpy`s. A malicious configuration
|
// TODO(fusion): Ughh... Get rid of all `strcpy`s. A malicious configuration
|
||||||
|
|||||||
107
src/crypto.cc
107
src/crypto.cc
@ -1,3 +1,108 @@
|
|||||||
#include "crypto.hh"
|
#include "crypto.hh"
|
||||||
|
|
||||||
// TODO
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
|
static void DumpOpenSSLErrors(const char *Where, const char *What){
|
||||||
|
error("OpenSSL error(s) while executing %s at %s:\n", What, Where);
|
||||||
|
ERR_print_errors_cb(
|
||||||
|
[](const char *str, usize len, void *u) -> int {
|
||||||
|
// NOTE(fusion): These error strings already have trailing newlines,
|
||||||
|
// for whatever reason.
|
||||||
|
error("> %s", str);
|
||||||
|
return 1;
|
||||||
|
}, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TRSAPrivateKey
|
||||||
|
// =============================================================================
|
||||||
|
TRSAPrivateKey::TRSAPrivateKey(void){
|
||||||
|
m_RSA = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRSAPrivateKey::~TRSAPrivateKey(void){
|
||||||
|
if(m_RSA){
|
||||||
|
RSA_free(m_RSA);
|
||||||
|
m_RSA = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TRSAPrivateKey::initFromFile(const char *FileName){
|
||||||
|
if(m_RSA != NULL){
|
||||||
|
error("TRSAPrivateKey::init: Key already initialized.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *File = fopen(FileName, "rb");
|
||||||
|
if(File == NULL){
|
||||||
|
error("TRSAPrivateKey::initFromFile: Failed to open \"%s\".\n", FileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_RSA = PEM_read_RSAPrivateKey(File, NULL, NULL, NULL);
|
||||||
|
fclose(File);
|
||||||
|
|
||||||
|
if(m_RSA == NULL){
|
||||||
|
error("TRSAPrivateKey::initFromFile: Failed to read key from \"%s\".\n", FileName);
|
||||||
|
DumpOpenSSLErrors("TRSAPrivateKey::initFromFile", "PEM_read_RSAPrivateKey");
|
||||||
|
}else if(RSA_size(m_RSA) != 128){
|
||||||
|
error("TRSAPrivateKey::initFromFile: File \"%s\" doesn't contain a 1024-bit key", FileName);
|
||||||
|
RSA_free(m_RSA);
|
||||||
|
m_RSA = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TRSAPrivateKey::decrypt(uint8 *Data){
|
||||||
|
if(m_RSA == NULL){
|
||||||
|
error("TRSAPrivateKey::decrypt: Key not initialized.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(fusion): Pass in the length of `Data` for checking.
|
||||||
|
ASSERT(RSA_size(m_RSA) == 128);
|
||||||
|
|
||||||
|
if(RSA_private_decrypt(128, Data, Data, m_RSA, RSA_NO_PADDING) == -1){
|
||||||
|
DumpOpenSSLErrors("TRSAPrivateKey::decrypt", "RSA_private_decrypt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TXTEASymmetricKey
|
||||||
|
// =============================================================================
|
||||||
|
void TXTEASymmetricKey::init(TReadBuffer *Buffer){
|
||||||
|
m_SymmetricKey[0] = Buffer->readQuad();
|
||||||
|
m_SymmetricKey[1] = Buffer->readQuad();
|
||||||
|
m_SymmetricKey[2] = Buffer->readQuad();
|
||||||
|
m_SymmetricKey[3] = Buffer->readQuad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TXTEASymmetricKey::encrypt(uint8 *Data){
|
||||||
|
// TODO(fusion): This assumes both data endpoints have the same byte order.
|
||||||
|
// It's unlikely that there is anything other than little-endian but we
|
||||||
|
// should use a few helping functions to ensure compatibility.
|
||||||
|
uint32 Sum = 0x00000000UL;
|
||||||
|
uint32 Delta = 0x9E3779B9UL;
|
||||||
|
uint32 V0 = *(uint32*)(&Data[0]);
|
||||||
|
uint32 V1 = *(uint32*)(&Data[4]);
|
||||||
|
for(int i = 0; i < 32; i += 1){
|
||||||
|
V0 += (((V1 << 4) ^ (V1 >> 5)) + V1) ^ (Sum + m_SymmetricKey[Sum & 3]);
|
||||||
|
Sum += Delta;
|
||||||
|
V1 += (((V0 << 4) ^ (V0 >> 5)) + V0) ^ (Sum + m_SymmetricKey[(Sum >> 11) & 3]);
|
||||||
|
}
|
||||||
|
*(uint32*)(&Data[0]) = V0;
|
||||||
|
*(uint32*)(&Data[4]) = V1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TXTEASymmetricKey::decrypt(uint8 *Data){
|
||||||
|
// TODO(fusion): Same as above.
|
||||||
|
uint32 Sum = 0xC6EF3720UL;
|
||||||
|
uint32 Delta = 0x9E3779B9UL;
|
||||||
|
uint32 V0 = *(uint32*)(&Data[0]);
|
||||||
|
uint32 V1 = *(uint32*)(&Data[4]);
|
||||||
|
for(int i = 0; i < 32; i += 1){
|
||||||
|
V1 -= (((V0 << 4) ^ (V0 >> 5)) + V0) ^ (Sum + m_SymmetricKey[(Sum >> 11) & 3]);
|
||||||
|
Sum -= Delta;
|
||||||
|
V0 -= (((V1 << 4) ^ (V1 >> 5)) + V1) ^ (Sum + m_SymmetricKey[Sum & 3]);
|
||||||
|
}
|
||||||
|
*(uint32*)(&Data[0]) = V0;
|
||||||
|
*(uint32*)(&Data[4]) = V1;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,52 +2,20 @@
|
|||||||
#define TIBIA_CRYPTO_HH_ 1
|
#define TIBIA_CRYPTO_HH_ 1
|
||||||
|
|
||||||
#include "common.hh"
|
#include "common.hh"
|
||||||
|
#include <openssl/rsa.h>
|
||||||
// TODO(fusion): We might want to scrap this implementation and use OpenSSL instead.
|
|
||||||
|
|
||||||
struct vlong_flex_unit{
|
|
||||||
uint32 n;
|
|
||||||
uint32 *a;
|
|
||||||
uint32 z;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vlong_value: vlong_flex_unit {
|
|
||||||
uint32 share;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vlong{
|
|
||||||
vlong_value *value;
|
|
||||||
int negative;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vlong_montgomery{
|
|
||||||
vlong R;
|
|
||||||
vlong R1;
|
|
||||||
vlong m;
|
|
||||||
vlong n1;
|
|
||||||
vlong T;
|
|
||||||
vlong k;
|
|
||||||
uint32 N;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TRSAPrivateKey{
|
struct TRSAPrivateKey{
|
||||||
TRSAPrivateKey(void);
|
TRSAPrivateKey(void);
|
||||||
~TRSAPrivateKey(void);
|
~TRSAPrivateKey(void);
|
||||||
void init(const char *PrimeP, const char *PrimeQ);
|
void initFromFile(const char *FileName);
|
||||||
void decrypt(uint8 *Data); // single 128 bytes block
|
void decrypt(uint8 *Data); // single 128 bytes block
|
||||||
|
|
||||||
// DATA
|
// DATA
|
||||||
// =================
|
// =================
|
||||||
vlong m_PrimeP;
|
RSA *m_RSA;
|
||||||
vlong m_PrimeQ;
|
|
||||||
vlong m_U;
|
|
||||||
vlong m_DP;
|
|
||||||
vlong m_DQ;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TXTEASymmetricKey{
|
struct TXTEASymmetricKey{
|
||||||
TXTEASymmetricKey(void);
|
|
||||||
~TXTEASymmetricKey(void);
|
|
||||||
void init(TReadBuffer *Buffer);
|
void init(TReadBuffer *Buffer);
|
||||||
void encrypt(uint8 *Data); // single 8 bytes block
|
void encrypt(uint8 *Data); // single 8 bytes block
|
||||||
void decrypt(uint8 *Data); // single 8 bytes block
|
void decrypt(uint8 *Data); // single 8 bytes block
|
||||||
|
|||||||
@ -216,7 +216,7 @@ void LoadWorldConfig(void){
|
|||||||
static void InitAll(void){
|
static void InitAll(void){
|
||||||
try{
|
try{
|
||||||
ReadConfig();
|
ReadConfig();
|
||||||
//SetQueryManagerLoginData(1, WorldName);
|
SetQueryManagerLoginData(1, WorldName);
|
||||||
LoadWorldConfig();
|
LoadWorldConfig();
|
||||||
InitSHM(!BeADaemon);
|
InitSHM(!BeADaemon);
|
||||||
LockGame();
|
LockGame();
|
||||||
|
|||||||
@ -187,4 +187,6 @@ struct TQueryManagerPoolConnection{
|
|||||||
TQueryManagerConnection *QueryManagerConnection;
|
TQueryManagerConnection *QueryManagerConnection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SetQueryManagerLoginData(int Type, const char *Data);
|
||||||
|
|
||||||
#endif //TIBIA_QUERY_HH_
|
#endif //TIBIA_QUERY_HH_
|
||||||
|
|||||||
15
tibia.pem
Normal file
15
tibia.pem
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXAIBAAKBgQDLoibNahc41DeQhZUTth3FrhMNYek5xbQrlZ0O4BFr0LukdGY1
|
||||||
|
A3xHKAXt4d6Y539cQxpKqVPb+eSo44076c1PfL31BTDNFToN4uB3eUsOw3hROPSx
|
||||||
|
0Jkh72FAIhl6QynId0AHyrqeAgY59ZsTyXyJCSCWpFnl0WvK3Qf6nVBH/wIDAQAB
|
||||||
|
AoGAB9DoA19sl8JRhasS70hAuUs2sP9Ol+iWQ0wBVMZV9Nj0stnC6IsDNKn9HEXc
|
||||||
|
qOrN0SlEM5RvQxTC6ZaeX6vYNQDSJj/aigSyiNTMvw+38TD09z6EBlI4+0piGIJd
|
||||||
|
qY1ky0w3bdVhWiY2VFyGZ50NkfwjrpZSdLmsbhExzR4b/mkCQQDldLUeePo3RKZD
|
||||||
|
7+CVLFkTX/Yof8RLPOh1nukgftpvgaGcD1FXSwrIyKCHVAuwFnGgPfEr/2OAj60D
|
||||||
|
7Ya6XPeHAkEA4zC3U67ukzQxfyELrLTUBnsnKfkxejySsJ/M29SKCuHV2NOWxO8W
|
||||||
|
s9/c0RFvp0wI4uOxH00fIPYyI2h6TpxZyQJBAKQ0ZPktskKjCilMHPgkCIro/Yv2
|
||||||
|
A0+kgubJliP/I+rwZer8u0UxGsKdcOPnrYWSSjZWnaTS2y5Bo5tP/D6aETkCQDAc
|
||||||
|
AtZPtumpJcob/1LlP/jXX2W+BUIzTYTlcgYjLdA8HoK527V8Q7x3bVVAcfplWYRi
|
||||||
|
XwGX3T2npNpmp2+6IDECQBZuNbXiwHhDdsH7sSt36BGTFJNtVk3GJl/Bf50VrL6N
|
||||||
|
6NBNU3d4jQwArvSsanFYrZw+ayxS4rcJdZasO5mm+EI=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
71
tools/genpem.go
Normal file
71
tools/genpem.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
P = "1201758001370723323398753778257470257713354828752713123415294815" +
|
||||||
|
"0506251412291888866940292054989907714155267326586216043845592229" +
|
||||||
|
"084368540020196135619327879"
|
||||||
|
|
||||||
|
Q = "1189892136861686835188050824611210139447876026576932541274639840" +
|
||||||
|
"5473436969889506919017477758618276066588858607419440134394668095" +
|
||||||
|
"105156501566867770737187273"
|
||||||
|
|
||||||
|
E = "65537"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// NOTE(fusion): Generate key from known P, Q, and E. There isn't a helper
|
||||||
|
// function from the standard library so we need to build the private key
|
||||||
|
// ourselves.
|
||||||
|
p, ok := new(big.Int).SetString(P, 10)
|
||||||
|
if !ok || !p.ProbablyPrime(4) {
|
||||||
|
panic("invalid P")
|
||||||
|
}
|
||||||
|
|
||||||
|
q, ok := new(big.Int).SetString(Q, 10)
|
||||||
|
if !ok || !q.ProbablyPrime(4) {
|
||||||
|
panic("invalid Q")
|
||||||
|
}
|
||||||
|
|
||||||
|
e, ok := new(big.Int).SetString(E, 10)
|
||||||
|
if !ok || !e.IsInt64() || !e.ProbablyPrime(4) {
|
||||||
|
panic("invalid E")
|
||||||
|
}
|
||||||
|
|
||||||
|
pMinus1 := new(big.Int).Sub(p, big.NewInt(1))
|
||||||
|
qMinus1 := new(big.Int).Sub(q, big.NewInt(1))
|
||||||
|
gcd := new(big.Int).GCD(nil, nil, pMinus1, qMinus1)
|
||||||
|
phi := new(big.Int).Mul(pMinus1, qMinus1)
|
||||||
|
lambda := new(big.Int).Div(phi, gcd)
|
||||||
|
d := new(big.Int).ModInverse(e, lambda)
|
||||||
|
n := new(big.Int).Mul(p, q)
|
||||||
|
|
||||||
|
privateKey := rsa.PrivateKey{
|
||||||
|
PublicKey: rsa.PublicKey{
|
||||||
|
N: n,
|
||||||
|
E: int(e.Int64()),
|
||||||
|
},
|
||||||
|
D: d,
|
||||||
|
Primes: []*big.Int{p, q},
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(fusion): `Validate()` will only perform minor sanity checks. To actually
|
||||||
|
// check that the output key is valid use `openssl rsa -in KEY.PEM -check`.
|
||||||
|
if err := privateKey.Validate(); err != nil {
|
||||||
|
panic("invalid private key: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(fusion): Dump private key into stdout.
|
||||||
|
block := pem.Block{
|
||||||
|
Type: "RSA PRIVATE KEY",
|
||||||
|
Bytes: x509.MarshalPKCS1PrivateKey(&privateKey),
|
||||||
|
}
|
||||||
|
pem.Encode(os.Stdout, &block)
|
||||||
|
}
|
||||||
@ -21,11 +21,13 @@ var (
|
|||||||
"-Wno-unused-parameter",
|
"-Wno-unused-parameter",
|
||||||
"-Wno-format-truncation",
|
"-Wno-format-truncation",
|
||||||
"-std=c++11",
|
"-std=c++11",
|
||||||
|
"-pthread",
|
||||||
"-DOS_LINUX=1",
|
"-DOS_LINUX=1",
|
||||||
"-DARCH_X64=1",
|
"-DARCH_X64=1",
|
||||||
}
|
}
|
||||||
linkerOptions = []string{
|
linkerOptions = []string{
|
||||||
"-Wl,-t",
|
"-Wl,-t",
|
||||||
|
"-lcrypto",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -93,7 +95,7 @@ func main() {
|
|||||||
fmt.Fprintf(&output, " $(BUILDDIR)/%v", object.obj)
|
fmt.Fprintf(&output, " $(BUILDDIR)/%v", object.obj)
|
||||||
}
|
}
|
||||||
fmt.Fprint(&output, "\n")
|
fmt.Fprint(&output, "\n")
|
||||||
fmt.Fprint(&output, "\t$(CC) $(CFLAGS) $(LFLAGS) -o $@ $^\n\n")
|
fmt.Fprint(&output, "\t$(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)\n\n")
|
||||||
|
|
||||||
// OBJECTS
|
// OBJECTS
|
||||||
for _, object := range objectFiles {
|
for _, object := range objectFiles {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user