Just to show-off power of nim:
import macros
import math
import unsigned
proc `xor` *(x, y: char): char {.magic: "BitxorI", noSideEffect.}
proc fnv32a*[T: string|openArray[char]|openArray[uint8]|openArray[int8]](data: T): int32 =
result = -18652613'i32
for b in items(data):
result = result xor ord(b)
result = result *% 16777619
proc fnv64a*[T: string|openArray[char]|openArray[uint8]|openArray[int8]](data: T): int64 =
result = -5472609002491880000'i64
for b in items(data):
result = result xor ord(b)
result = result * 1099511628211'i64
proc decode_xs*(s: string, key: int32): string =
var k = key
result = newString(s.len)
for i in s.low .. s.high:
result[i] = s[i]
result[i] = result[i] xor chr(uint8(k and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 8) and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 16) and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 24) and 0xFF))
k = k +% 1
proc encode_xs*(s: string, key: int32): string = decode_xs(s, key)
var xs_counter {.compiletime.}: int32 = fnv32a(CompileTime & CompileDate) and 0x7FFFFFFF
macro xs*(s: expr): expr {.immediate.} =
var xs_s = encode_xs($s, xs_counter)
var var_name = "_xs_string_" & $xs_counter
echo($xs_counter)
result = new_stmt_list(
new_nim_node(nnkVarSection).add(
new_nim_node(nnkIdentDefs).add(
new_ident_node(var_name),
new_nim_node(nnkEmpty),
new_nim_node(nnkCall).add(
bind_sym("decode_xs"),
new_str_lit_node(xs_s),
new_int_lit_node(xs_counter)
)
)
),
new_ident_node(var_name)
)
xs_counter = (xs_counter *% 16777619) and 0x7FFFFFFF
when is_main_module:
echo xs("invisible")
echo xs("strings")
Resulting strings in compiled code:
STRING_LITERAL(TMP275, "__FZA\245\257\242\252", 9);
STRING_LITERAL(TMP276, "%!&:<6#", 7);
And on every rebuild those constants change. So next thing you build in nim can have strings like "invalid license" or "cheat dected" hidden from those pesky reverse-engineers ;)
And on every rebuild those constants change.
I don't get it. Where does the claimed non-determinism come from?
If someone's still interested in this, updated code for latest Nim:
import macros
proc `xor` *(x, y: char): char {.magic: "BitxorI", noSideEffect.}
proc fnv32a*[T: string|openArray[char]|openArray[uint8]|openArray[int8]](data: T): int32 =
result = -18652613'i32
for b in items(data):
result = result xor int32(ord(b))
result = result *% 16777619
proc decodeStr*(s: string, key: int32): string =
var k = key
result = newString(s.len)
for i in s.low .. s.high:
result[i] = s[i]
result[i] = result[i] xor chr(uint8(k and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 8) and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 16) and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 24) and 0xFF))
k = k +% 1
proc encodeStr*(s: string, key: int32): string = decodeStr(s, key)
var encodedCounter {.compiletime.}: int32 = fnv32a(CompileTime & CompileDate) and 0x7FFFFFFF
macro xs*(s: untyped): untyped =
var encodedStr = encodeStr($s, encodedCounter)
result = quote do:
decodeStr(`encodedStr`, `encodedCounter`)
encodedCounter = (encodedCounter *% 16777619) and 0x7FFFFFFF
when isMainModule:
echo xs("invisible")
echo xs("strings")
Thanks for @LeFF to discovering that thread, with it the code becomes:
import macros
type
estring = distinct string
proc `xor`*(x, y: char): char {.magic: "BitxorI", noSideEffect.}
proc fnv32a*[T: string|openArray[char]|openArray[uint8]|openArray[int8]](data: T): int32 =
result = -18652613'i32
for b in items(data):
result = result xor int32(ord(b))
result = result *% 16777619
proc decodeStr*(s: estring, key: int32): string =
var s = string(s)
var k = key
result = newString(s.len)
for i in s.low .. s.high:
result[i] = s[i]
result[i] = result[i] xor chr(uint8(k and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 8) and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 16) and 0xFF))
result[i] = result[i] xor chr(uint8((k shr 24) and 0xFF))
k = k +% 1
proc encodeStr*(s: string, key: int32): estring = estring(decodeStr(estring(s), key))
var encodedCounter {.compiletime.}: int32 = fnv32a(CompileTime & CompileDate) and 0x7FFFFFFF
# term rewriting macro
macro encrypt*{s}(s: string{lit}): untyped =
var encodedStr = encodeStr($s, encodedCounter)
result = quote do:
decodeStr(estring(`encodedStr`), `encodedCounter`)
encodedCounter = (encodedCounter *% 16777619) and 0x7FFFFFFF
# test-case
echo "hello"
Or you could even import this code from other modules and all string literals in them will automatically get encrypted :)
sorry to reply for the old post Does this technology work for latest nim, for example
Nim Compiler Version 1.5.1 [Windows: amd64]
Compiled at 2021-03-18
and the test code is from strenc
import strenc
# After importing the module you don't have to do anything else to activate encryption
echo "hello world"
echo "how are you?"
and I use the command line
nim c -c -d:release --hint[Pattern]:off c.nim
to get nimcache\c_r\@mc.nim.c in which, however, I can read the original string
/* section: NIM_merge_DATA */
STRING_LITERAL(TM__PWLVblvdk3wLpEhn9cPvLyw_3, "hello world", 11);
static NIM_CONST tyArray__nHXaesL0DJZHyVS07ARPRA TM__PWLVblvdk3wLpEhn9cPvLyw_2 = {((NimStringDesc*) &TM__PWLVblvdk3wLpEhn9cPvLyw_3)}
;
STRING_LITERAL(TM__PWLVblvdk3wLpEhn9cPvLyw_5, "how are you\?", 12);
static NIM_CONST tyArray__nHXaesL0DJZHyVS07ARPRA TM__PWLVblvdk3wLpEhn9cPvLyw_4 = {((NimStringDesc*) &TM__PWLVblvdk3wLpEhn9cPvLyw_5)}
;
so what is the problem?
Well, first of all - strenc is an simple experiment :)
About your issue - strings are not encrypted because they're used right away, so even if the term-rewriting macro encrypts them, the compiler decrypts them back since they're known at compile-time.
strenc does a good job.
However I have met some strings without been encrypted if the code has several hundred line as Yardanico have stated.
Is there any way to treat all string?
The answer is I need some way to protect my data from been extracting easily for common users. A weak protection goes well.
But I am too lazy to encrypt every string to a hard-to-be-judged variable then use the decrypted string by adding, something like, decrypted(strCryptedName), decrypted(strCryptedAddress)