> Having a user define a verb at runtime is a bit unusual. More typical would
> be to have them supply the password in a text field, and then creating the
> verb from that (which you could do automatically, obviously).
> pwdcheck =: localvar&('password' [:`(dostuff@[)@.-: ])
Its for a 2 stage disk/file decryption process. Such functions are supposed to
be time consuming in order to protect from password lookup tables. This is all
to enable the dangerous idea of speeding up the process at user option by
keeping the 2nd stage results in memory.
where localvar =. f 'password' ('password' may be result of hashing)
f =: 2:
erasefile =: 1!:55 NB. overwrite with random prior?
lrA =:1 : '5!:5 < ''u'''
lockedE =: 2 : 0 NB. creates locked function from linear expression m
a =. '%j =: %j' sprintf n;m
(3!:6 ] a) 1!:2 fl =. < jpath '~temp\filet.ijl'
0!:0 fl
erasefile fl )
Making a password protected function
pwprotF =: 2 : 0
a =. u n
1 : (a lrA , '&(0:`(u@:[)@.(', n lrA ,' -: ]))')
)
'password' 1 : '+: f pwprotF m'2&(0:`(+:@:[)@.('password' -: ]))
'password' (1 : '+: f_base_ pwprotF m' lrA (lockedE 'pwcheck'))
pwcheck is locked. parens indicate namable adverb
pwcheck 'password'
4
pwcheck 'passwor'
0
This would be protection from evil maid "bathroom" attack who cannot take a
camera screenshot of a definition of 'password' by simply invoking a console
(and a 5 second movie hack), and the program can furthermore run without
attached console, and as root, so only root privileged viruses/debug tools
could query memory(?).
The user does just enter 'password' in a prompt to create the locked verb.
----- Original Message -----
From: Dan Bron <[email protected]>
To: J Programming <[email protected]>
Cc:
Sent: Tuesday, August 11, 2015 11:23 AM
Subject: Re: [Jprogramming] unlock.ijs
> Btw, the only secret I want to keep safe is the noun 'password' by embedding
> it in a locked verb
If you’re really concerned about the security of this password, it should not
appear in memory in cleartext at all. You should only deal in hashes and
comparing hashes.
> that is set at run time,
Having a user define a verb at runtime is a bit unusual. More typical would be
to have them supply the password in a text field, and then creating the verb
from that (which you could do automatically, obviously).
> pwdcheck =: localvar&('password' [:`(dostuff@[)@.-: ])
Again, where the 8 letters p a s s w o r d coming from? Is someone typing in
the full sentence pwdcheck =: localvar&(‘password’ …) into the session
manager, manually, every time J is started? (I ask because if that’s *not* the
case then you’ve got more points in the workflow where the password could be
intercepted, even before the name is locked by 3!:6.)
> Does 9!:25 disable the 15!:n commands?
Nope. And security level (9!:25) is extremely out of date; I wouldn’t rely on
it in general [1].
> Though I don't see a single bit difference in an int there.
Yes, that’s what I meant by “requires more pointer chasing” yesterday. I don’t
have a complete understanding of the J engine’s memory layout yet, but these
structures in turn point to other structures, and somewhere down the chain,
there’s a struct A with a flags field (second word) having the VLOCK bit set.
It would/will take more investigation to understand how to get from the
structures we have in hand to the ultimate structure containing the value of
pwdcheck. It’s a SMOP ;)
Incidentally, the only differences in the memory dumps you quoted:
> 56 0 184 262144 2 1 0 6443034000 6443033120 626935840960
>
> 56 0 184 262144 1 1 0 6443034000 6443033120 625002615568
Are in the 5th and final integers. The 5th integer is a reference count. If you
delete one of the names pointing to pwdcheck (e.g. erase’pwdcheck’) and call
memr again, you’ll see that 2 change to a 1 (or, vice versa, point another name
to the 2nd memory structure, and you’ll see its reference count go up).
Note that the initial 56 in the original data dumps indicate the “ravel”,
“value”, or “data” section of the struct starts after 56 bytes, or seven 8-byte
integers (on my 64-bit machine). Therefore everything from 6443034000
6443033120 .. onwards is considered the “value” of this array. I haven’t yet
worked out what these initial two values mean, but the third value, the one
that differs in the two arrays above, I believe is a pointer to the name (or
one of the names?) for the verb. If you do
SZI =: IF64 { 4 8
a =: memr (15!:14 <'PWDCHECK'), 0, 1, JINT
memr a,(SZI*9),1,JINT
140205391245200
namen =: memr a,(SZI*9),1,JINT
memr namen,0,16,JINT
64 0 48 33554432 2 8 1 8 10699157 0 0 7307199678560337928 27491 0 0 7
You’ll see the 4th integer here, type, is 33554432 (2^25), which means “name”
[2]. The 8 1 8 bit changes depending on which name you’re inspecting. I
originally though the 8 corresponded to the 8 characters in ‘pwdcheck’, but on
further investigation that turned out to be a red herring (then I thought maybe
the 8 was an index into the global symbol table, but 8 seems suspiciously low
for a name created so late in the J session).
The subsequent six values in the original arrays,
> 0 0 0 9223372036854775807 9223372036854775807 9223372036854775807
have been the same in all verbs I’ve inspected so far, and look like sentinels
to me (3 3 # 0, 2^64-1): three pairs of mins and maxes?
Finally, if you read a little further into memory, you’ll find several more
pointers until you hit the next entry in table (i.e. the next series of bytes
which follow the same pattern as the two arrays quoted above). It may be in
these pointers that the value of the verb pwdcheck is hidden.
All we know is it’s there somewhere, and therefore with enough effort we can
expose it.
> I guess even if it did, external processes can read memory.
Yes, this is what I meant with my advice that 3!:6 is merely an encoding, not
true encryption. I promise you the string ‘password’ appears *somewhere* in the
J process’ memory (else -: couldn’t match against it).
The advantage we have from doing this inside of J is we have a handle on where
to start (i.e. with 15!:6), but in theory a process with access to J’s memory
(if not protected by the OS and/or hardware exceptions) could just scan the
whole thing looking, seriatim, for likely strings. Even if 15!:6 were taken
away from us in J completely, we could simulate this memory-scanning starting
from square one with 15!:0 (call external library, likely OS APIs).
All I want to drive home is that this security model is breakable. Certainly
using 3!:6 makes it *harder* to access your sensitive data, and that’s a good
thing, but it should not lull you into a false sense of perfect, or even
particularly high, security.
-Dan
[1] security level out of date
http://www.jsoftware.com/jwiki/System/Interpreter/Bugs#security_level_out_of_date
<http://www.jsoftware.com/jwiki/System/Interpreter/Bugs#security_level_out_of_date>
[2] Interpretations of struct A’s “type” field:
https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/jtype.h#L123
<https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/jtype.h#L123>
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm