Rebol Product Suggestion.
[1/11] from: ptretter:charter at: 22-Jun-2001 14:42
Heres an idea - just make two scripts - one of the scripts converts a script
file into some binary system that you define and then another that you
create interprets the binary script you dumped. That way you can distribute
the interpreter and script processor along with your encyrpted/binary
script.
Paul Tretter
[2/11] from: depotcity::telus::net at: 22-Jun-2001 13:24
But then the user could use the interpreter to read the script. However, I
think your on the right track. You could have an encrypted script that was
decrypted by reading a decryption string from a server.. but that is slow,
requires network access etc.
There must be a more effective method???
Terry
[3/11] from: depotcity:telus at: 22-Jun-2001 10:40
Hi.
Here's a Rebol product that I would buy.
An script encapsulator that simply converts a script to binary form, but unlike the runtime,
without the core/command engine attached.
Just something to prevent short scripts from being read.
With the runtime, if you encapsulate a 1kb script, you end up with a 254kb monster!
Terry Brownell
[4/11] from: holger:rebol at: 22-Jun-2001 10:50
On Fri, Jun 22, 2001 at 10:40:16AM -0700, Terry Brownell wrote:
> Hi.
>
> Here's a Rebol product that I would buy.
>
> An script encapsulator that simply converts a script to binary form, but unlike the
runtime, without the core/command engine attached.
>
> Just something to prevent short scripts from being read.
REBOL would have to convert it back to text form in order to interpret it, and at that
time users would still see the script.
--
Holger Kruse
[holger--rebol--com]
[5/11] from: dness:home at: 22-Jun-2001 13:54
Terry Brownell wrote:
> Hi.
>
> Here's a Rebol product that I would buy.
>
> An script encapsulator that simply converts a script to binary form, but unlike the
runtime, without the core/command engine attached.
>
> Just something to prevent short scripts from being read.
>
> With the runtime, if you encapsulate a 1kb script, you end up with a 254kb monster!
>
> Terry Brownell
>
I'm not sure I'd use `monster' to describe a 254kb file.
Cluster size on my most recent large disk is 256kb. anyway, so
such things don't really cost me all that much.
I wonder if things like this will worry us for long?
[6/11] from: g:santilli:tiscalinet:it at: 23-Jun-2001 15:00
Hello Terry!
On 22-Giu-01, you wrote:
TB> But then the user could use the interpreter to read the
TB> script. However, I think your on the right track. You could
TB> have an encrypted script that was decrypted by reading a
TB> decryption string from a server.. but that is slow, requires
TB> network access etc. There must be a more effective method???
Encryption never gives you security over source code. To execute
you have to decrypt, so any user has to be able to decrypt. This
means that encryption is just a waste of time in this case --- why
not just use compression instead?
Please consider that even .exe binary files are "readable", in the
sense that you can disassemble the machine language etc. Of
course, very few people wants to disasseble and reverse engeneer a
big and complex program, and this is what makes people happy about
distributing binary only programs.
In the case of REBOL, noone stops you from creating a very
unreadable script that cannot be (easyly) understood or modified
by a human but that can be evaluated by the REBOL interpreter. The
alien language
script from the library is an example, and you
can get even more trickier if you want (e.g. hiding checksums
around so that modifing is intercepted by the program).
What I'd do is creating a script that takes a normal (commented,
readable etc.) REBOL script and writes out another script that
does exactly the same thing as the first but is not readable by
humans. (I'm likely to write something like this sooner or later
as I might need it.)
Regards,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
[7/11] from: joel:neely:fedex at: 23-Jun-2001 4:18
Hi, Gabriele,
Your remarks are inspiring, as usual! (Of course there's
a fine line between inspiration and madness. ;-)
Gabriele Santilli wrote:
> Encryption never gives you security over source code. To
> execute you have to decrypt, so any user has to be able to
> decrypt.
>
Unless RT adds a primitive that's the equivalent of
do decrypt somestring
somestring: ""
(per a discussion at least a year ago on this list).
> In the case of REBOL, noone stops you from creating a very
> unreadable script that cannot be (easyly) understood or
<<quoted lines omitted: 4>>
> another script that does exactly the same thing as the
> first but is not readable by humans.
I played with this idea a while back. We could begin with
8<--------------------------------------------------------
propercase: func [
{capitalize first letter only of a string}
s [string!] {original string - unchanged}
][
head change lowercase copy s uppercase copy/part s 1
]
ply: func [
{create a string from series and separator arguments}
ser [series!] {series of values to be collected}
sep [string! char!] {value to go between elements}
/local
result {accumulator for string}
nextsep {what precedes next item?}
][
result: copy nextsep: ""
foreach item ser [
repend result [nextsep item]
nextsep: sep
]
result
]
map: func [
{return mapped-function results for all ser items}
[catch]
ser [block! hash! string!] {inputs}
mapped-function [any-function!]
/all {return none? values?}
/local
res {result block}
val {single-item result value}
][
res: make type? ser length? ser
throw-on-error [
foreach item ser [
if any [
found? val: mapped-function item
all
][
append/only res val
]
]
]
res
]
capitalize: func [
{return string with uppercased first letters}
s [string!] {unmodified input}
][
ply map parse s none :propercase " "
]
8<--------------------------------------------------------
And apply rules such as:
- Remove comments.
- Never allow meaningful names
- Use names hard to distinguish
- Replace simple constants/expressions with more obscure
expressions
- Never allow whitespace to reveal structure
and arrive at
8<--------------------------------------------------------
capitalize: func [ I1l1I [string!] /local O0Ol0 IIOOO ] [
O0Ol0: func [ OO01O [series!] O00I0 [string! char!] /local
OOOIO O0010 ] [ OOOIO: copy O0010: copy tail mold 17 foreach
O0OIO OO01O [ repend OOOIO [O0010 O0OIO] O0010: O00I0 ]
OOOIO ] IIOOO: func [ IIOOI [block! hash! string!] IIOO1
[any-function!] /IIO0I /local II000 III0l ] [ II000: make
type? IIOOI length? IIOOI foreach II1Ol IIOOI [ if any [
found? III0l: IIOO1 II1Ol IIO0I ] [ append/only II000 III0l
] ] II000 ] O0Ol0 IIOOO parse I1l1I none func [ lOOO1
[string!] ] [ head change lowercase copy lOOO1 uppercase
copy/part lOOO1 index? head lOOO1 ] to-string to-char 32 ]
8<--------------------------------------------------------
> (I'm likely to write something like this sooner or later
> as I might need it.)
>
However, I found that some of those rules were VERY hard to
describe in purely syntactic terms, actually requiring an
ability to read and understand REBOL. Since I'm still
working on creating a model that *I* can understand, I don't
yet know how to program the required knowledge. I'll be
fascinated to see any progress you might make! Good luck!
-jn-
------------------------------------------------------------
Programming languages: compact, powerful, simple ...
Pick any two!
joel'dot'neely'at'fedex'dot'com
[8/11] from: g:santilli:tiscalinet:it at: 24-Jun-2001 12:09
Hello Joel!
On 23-Giu-01, you wrote:
JN> Your remarks are inspiring, as usual! (Of course there's
JN> a fine line between inspiration and madness. ;-)
;-)
JN> Unless RT adds a primitive that's the equivalent of
JN> do decrypt somestring
JN> somestring: ""
JN> (per a discussion at least a year ago on this list).
Yes, but then again with proper reverse engeneering one could get
to the source anyway. A "lossy" conversion, instead, guarantees
that noone can get to the original source in any way.
JN> propercase: func [
JN> {capitalize first letter only of a string}
JN> s [string!] {original string - unchanged}
JN> ][
JN> head change lowercase copy s uppercase copy/part s 1
JN> ]
what about:
propercase: func [s] [head lowercase next uppercase/part copy s 1]
JN> result: copy nextsep: ""
BTW, in these cases I usually write:
result: clear ""
; ...
copy result
because that will probably require less memory allocations. After
calling the function a couple times, indeed, the result buffer
will automatically end up being as large as needed and no more
memory allocations and copying will be needed in future calls,
except for the explicit final copy. (Well, I couldn't resist
giving my $0.02. :)
JN> And apply rules such as:
JN> - Remove comments.
;-comments will be removed by load. String comments could be
removed automatically in places such as function definitions etc.,
but maybe it would be better if is the programmer to manually
remove them.
JN> - Never allow meaningful names
This can be done by changing non-system words and by aliasing
system words. Human intervention may be necessary in some cases.
JN> - Use names hard to distinguish
I'd say completely random. :)
JN> - Replace simple constants/expressions with more obscure
JN> expressions
Mainly for strings, so that they are not easyly readable by the
intruder
.
JN> 8<--------------------------------------------------------
JN> capitalize: func [ I1l1I [string!] /local O0Ol0 IIOOO ] [
JN> O0Ol0: func [ OO01O [series!] O00I0 [string! char!] /local
JN> OOOIO O0010 ] [ OOOIO: copy O0010: copy tail mold 17 foreach
JN> O0OIO OO01O [ repend OOOIO [O0010 O0OIO] O0010: O00I0 ]
JN> OOOIO ] IIOOO: func [ IIOOI [block! hash! string!] IIOO1
JN> [any-function!] /IIO0I /local II000 III0l ] [ II000: make
JN> type? IIOOI length? IIOOI foreach II1Ol IIOOI [ if any [
JN> found? III0l: IIOO1 II1Ol IIO0I ] [ append/only II000 III0l
JN> ] ] II000 ] O0Ol0 IIOOO parse I1l1I none func [ lOOO1
JN> [string!] ] [ head change lowercase copy lOOO1 uppercase
JN> copy/part lOOO1 index? head lOOO1 ] to-string to-char 32 ]
JN> 8<--------------------------------------------------------
This is a very good example of what I intended. Thanks Joel!
JN> yet know how to program the required knowledge. I'll be
JN> fascinated to see any progress you might make! Good luck!
I'll need luck, I know! :-) But I think it can be done to some
extent, as long as either the programmer helps the tool doing the
conversion or (s)he writes the source code in a format that can be
easyly automatically processed (giving hints to the processor,
that is).
Regards,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
[9/11] from: joel:neely:fedex at: 24-Jun-2001 3:16
Gabriele Santilli wrote:
> JN> Unless RT adds a primitive that's the equivalent of
>
> JN> do decrypt somestring
> JN> somestring: ""
>
Let me detail this to
do-crypt: make native! [voodoo-stuff] [
hidden-buffer: decrypt voodoo-stuff
block-buffer: load hidden-buffer
clear hidden-buffer
do block-buffer
clear block-buffer
]
(terrible hypothetical REBOL style, just to make the point).
> Yes, but then again with proper reverse engeneering one could
> get to the source anyway. A "lossy" conversion, instead,
> guarantees that noone can get to the original source in any
> way.
>
Assuming that there's no such thing as perfectly secure
encryption, there's always *some* way to crack something. As
you pointed out earlier, compiled binaries can be analyzed and
disassembled. However, few people have sufficient time, money,
tools, skills, patience, and motivation (i.e., "cost" factors)
to reverse engineer a reasonably-sized binare.
IMHO the game is about simply raising the costs high enough that
most people won't bother. That's why I suggest the "do-crypt"
option. If the decrypted source only exists in a buffer long
enough for REBOL to load it to an internal data structure,
which only exists long enough to be DOne, and all of the above
is done within a native that can't be examined with SOURCE,
then the distributed source code is much more secure than if
the decryption were done by the user and/or left in a user-
accessible place in memory.
Of course, the attacker could still hook up a logic analyzer,
use an ICE debugger, or run a Pentium emulator on his friendly
neighborhood Beowulf, etc., but those options all raise the
costs beyond most users' means.
You're absolutely right that "shrouding" the code (in the sense
we were discussing and I illustrated) would further raise the
costs if combined with do-crypt.
> what about:
>
> propercase: func [s]
> [head lowercase next uppercase/part copy s 1]
>
Nice! (But you didn't show how that change would affect the
shrouded copy! ;-)
> JN> result: copy nextsep: ""
> BTW, in these cases I usually write:
<<quoted lines omitted: 7>>
> future calls, except for the explicit final copy. (Well, I
> couldn't resist giving my $0.02. :)
That's an interesting approach; let me think out loud...
result: copy ""
;...
result
... copies a trivial string initially, then reallocates and
copies (some number of times/quantities) as the result grows
during each function invocation.
result: clear ""
;...
copy result
... on repeated use: clears and copies a string with allocation
equal to the longest result produced in any use.
I can think of all sorts of interesting benchmarks for the
behavior of CLEAR, COPY, and APPEND (the hidden allocations)
but the surface-level trade-off would seem to be a variation
on the classical time-for-space. If an abnormally large result
occurred early in a long-running process, then option two would
keep that amount of memory tied up and subsequently unused
forever (i.e., until REBOL quits).
That being the case, does
result: make string! some-normally-large-enough-size
;...
result
sound like a middle-ground compromise to you?
> JN> - Replace simple constants/expressions with more obscure
> JN> expressions
>
> Mainly for strings, so that they are not easyly readable by
> the "intruder".
>
Depending on the application, one may be as likely to want to
hide some "magic numbers" as well. The technique works for
both. Didn't you notice that I used
index? head lOOO1
as a shrouded way to get a 1? ;-)
> JN> yet know how to program the required knowledge. I'll be
> JN> fascinated to see any progress you might make! Good
> luck!
>
> I'll need luck, I know! :-) But I think it can be done to some
> extent...
>
Agreed. I had been thinking about the "full blown" problem
of taking an arbitrary REBOL source file and trying to shroud
it. Unfortunately, the task of figuring out which words were
my words versus system words (versus somebody-else's words?)
began to look quite hairy given the possibility of DO and BIND
appearing in the code.
One of the cleverest shrouding tricks I've seen used "key
words" randomly as replacements for local variables, etc.
The analog in REBOL would be to turn something like
ply: func [
{create a string from series and separator arguments}
ser [series!] {series of values to be collected}
sep [string! char!] {value to go between elements}
/local
result {accumulator for string}
nextsep {what precedes next item?}
][
result: copy nextsep: ""
foreach item ser [
repend result [nextsep item]
nextsep: sep
]
result
]
into
ply: func [print [series!] = [string! char!] /local
probe word? ] [ probe: copy word?: "" foreach to
print [ repend probe [ word? to ] word?: = ] probe ]
which actually works... ;-)
Highly effective shrouding IMHO, but requires even more
semantic knowledge of REBOL to pull it off.
-jn-
------------------------------------------------------------
Programming languages: compact, powerful, simple ...
Pick any two!
joel'dot'neely'at'fedex'dot'com
[10/11] from: g:santilli:tiscalinet:it at: 24-Jun-2001 23:12
Hello Joel!
On 24-Giu-01, you wrote:
JN> IMHO the game is about simply raising the costs high enough
JN> that most people won't bother. That's why I suggest the
Absolutely.
JN> Nice! (But you didn't show how that change would affect the
JN> shrouded copy! ;-)
Left as an exercise to the reader
. ;-)
JN> I can think of all sorts of interesting benchmarks for the
JN> behavior of CLEAR, COPY, and APPEND (the hidden allocations)
JN> but the surface-level trade-off would seem to be a variation
JN> on the classical time-for-space. If an abnormally large
JN> result occurred early in a long-running process, then option
JN> two would keep that amount of memory tied up and subsequently
JN> unused forever (i.e., until REBOL quits).
I think so...
JN> That being the case, does
JN> result: make string! some-normally-large-enough-size
JN> ;...
JN> result
JN> sound like a middle-ground compromise to you?
Yep. But it's not always that easy to choose
some-normally-large-enough-size in a way that makes everyone happy.
(Of course. :)
Anyway, I just thought that it would have been useful to point out
that there are many possibilities to choose from, and your
analisys will surely help choosing!
JN> Agreed. I had been thinking about the "full blown" problem of
JN> taking an arbitrary REBOL source file and trying to shroud
JN> it. Unfortunately, the task of figuring out which words were
JN> my words versus system words (versus somebody-else's words?)
JN> began to look quite hairy given the possibility of DO and
JN> BIND appearing in the code.
I think an acceptable solution could be the following:
* the programmer puts all the code together in a huge script.
* the tool loads the script and checks words versus what is in
system/words; if a word is in system/words, it is put in the
list of words to be aliased.
* the tool spits out some unreadable and tricky code to alias the
words in the list.
* all the other words are simply substituted.
What is more difficult is to find a way to automatically substitute
simple expressions or literal values with trickier ones. I think
this will need at least some human assistance. Any idea?
JN> ply: func [print [series!] = [string! char!] /local
JN> probe word? ] [ probe: copy word?: "" foreach to
JN> print [ repend probe [ word? to ] word?: = ] probe ]
This is nice, too. But I'm afraid it would be almost impossible to
do automatically... (as you point out, too)
Regards,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
[11/11] from: agem:crosswinds at: 25-Jun-2001 2:01
RE: [REBOL] Re: Rebol Product Suggestion.
[g--santilli--tiscalinet--it] wrote:
> Hello Joel!
>
> On 24-Giu-01, you wrote:
>
--snip--
> JN> ply: func [print [series!] = [string! char!] /local
> JN> probe word? ] [ probe: copy word?: "" foreach to
> JN> print [ repend probe [ word? to ] word?: = ] probe ]
>
> This is nice, too. But I'm afraid it would be almost impossible to
> do automatically... (as you point out, too)
>
[REBOL [
title: "translate rebol-scripts to another language"
content: true
file: %trans3.r
comment: {
had a quick look on hd, not sure what this is ;-)
feature: translates words in pathes too, so
this/that would go dies/das .
based on Carls %clean-script.r
PROTOTYP, own risks and that! ;-)
}
]
script-cleaner: make object! [
a: none
to-type: func [t w] [
do load mold compose/deep [to (type? :t) first [(:w)]]
]
any-path?: func [s] [
any [path? :s set-path? :s lit-path? :s]
]
deutsch: make hash! [
;rebol
= any-word? ein-wort?
any manche
append ha&ng-an
change a&ndere
clear sa&ubere
compose stelle-zusammen
copy kopiere
deep tief
difference unterschied
do tue
does tut
either entscheide
emit gib-aus
end text-ende
first erstes
forall *jeder
forskip *gruppiert
found? gefunden?
func rezept
hash schnellfinder
head anfang
if wenn
last letztes
load lade
mold rebol-text
newline neue-zeile
next danach
parse analysiere
pick nimm-nr
remove entferne-an
set setze
select wa&hle-aus
skip u&berspringe
some einige
sort sortiere
tail ende
thru durch
to zu
true richtig
unique ohne-doppelte
;meins
a a
new neu
value wert
]
forskip deutsch 2 [change deutsch to string! first deutsch] deutsch: head deutsch
words: copy []
w: func [w /local e o] [
append words to word! :w
e: select deutsch to string! to word! :w
either e [to-type :w :e] [:w]
]
out: none ; output text
spaced: off ; add extra bracket spacing
indent: "" ; holds indentation tabs
emit-line: func [] [append out newline]
emit-space: func [pos] [
append out either newline = last out [indent] [
pick [#" " ""] found? any [
spaced
not any [find "[(" last out find ")]" first pos]
]
]
]
emit: func [from to] [emit-space from append out copy/part from to]
set 'clean-script func [
"Returns new script text with standard spacing."
script "Original Script text"
/spacey "Optional spaces near brackets and parens"
/local str new
] [
spaced: found? spacey
out: append clear copy script newline
parse script blk-rule: [
some [
str:
newline (emit-line) |
#";" [thru newline | to end] new: (emit str new) |
[#"[" | #"("] (emit str 1 append indent tab) blk-rule |
[#"]" | #")"] (remove indent emit str 1) |
skip (set [value new] load/next str
any [
if any-word? :value [emit a: mold w :value tail a true]
if any-path? :value [
forall value [if any-word? value/1 [value/1: w value/1]] value: head :value
emit a: mold :value tail a
true
]
do [emit str new]
]
) :new
]
]
remove out ; remove first char
]
dump: does [
probe sort unique script-cleaner/words
a: copy []
forskip deutsch 2 [append a to word! deutsch/1] deutsch: head deutsch
probe sort exclude words a
]
]
? 123
save f: system/script/header/file load/header system/script/header/content
print example: clean-script read f
;script-cleaner/dump
]
> Regards,
> Gabriele.
;-) Volker
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted