Showing posts with label newlisp. Show all posts
Showing posts with label newlisp. Show all posts

Tuesday, March 4, 2008

IP Subnetting - more fun with newLISP

I decided it would be fun to try to make an IP subnet calculator with newLISP.

Thanks to Elica and Lutz on the newLISP discussion boards. I needed some help with the logic. There's probably a way to compact this code down to about 3 lines somehow, but I'm still a newLISP n00b. I stuck with the logic examples that I have a firm understanding of, but the discussion yielded some interesting results.

Here's what I came up with


#!/usr/bin/newlisp
# newLISP IP Address calculator by ax0n
# ax0n (at) h-i-r.net
(define (iptostr ip4)
# Converts an integer to an IP in dotted decimal notation
(string
(mod (/ ip4 0x1000000) 0x100) "."
(mod (/ ip4 0x10000) 0x100) "."
(mod (/ ip4 0x100) 0x100) "."
(mod ip4 0x100))
)

(define (iptonum ip4str)
# Converts an IP string to an integer
(map set '(one two three four) (parse ip4str "."))
(+ (* 0x1000000 (float one)) (* 0x10000 (float two))
(* 0x100 (float three)) (float four))
)

(cond(
(< (length (main-args)) 3)
# Display usage if no args passed
(println "usage: ipcalc.lsp ip-address/maskbits")
(println "ex: ipcalc.lsp 192.168.1.20/24")
)
(true
(set 'ipstr (last(main-args)))
(map set '(ipaddr bits) (parse ipstr "/"))
(set 'binip (iptonum ipaddr))
(set 'netmask (& 0xffffffff ( << 0xffffffff (- 32 (int bits)))))
(set 'netaddr (& binip netmask))
(set 'bcast (& 0xffffffff (| binip (~ netmask))))
(println "host IP: " ipaddr )
(println "netmask: " (iptostr netmask) )
(println "network: " (iptostr netaddr) )
(println "broadcast: " (iptostr bcast))
(println "Host range: " (iptostr (+ netaddr 1))" - "(iptostr (- bcast 1)))
)
)
(exit)



Running it by itself gives you a syntax help page.

-bash-3.2$ ./ipcalc.lsp
usage: ipcalc.lsp ip-address/maskbits
ex: ipcalc.lsp 192.168.1.20/24

You have to provide an IP Address and mask in CIDR Notation. It does the rest!

-bash-3.2$ ./ipcalc.lsp 192.168.0.49/24
host IP: 192.168.0.49
netmask: 255.255.255.0
network: 192.168.0.0
broadcast: 192.168.0.255
Host range: 192.168.0.1 - 192.168.0.254


You can download the script here:
http://stuff.h-i-r.net/blogstuff/ipcalc.lsp

Saturday, February 10, 2007

newLISP OTP implementation

I had some free time, so I came up with something fun to play with.

I can't stress enough the importance of protocol when dealing with cryptography. Leaving no trace of the used portion of the pad nor the cleartext file is essential to maintaining the secrecy of your messages.

Some operating systems let you set flags or attributes on files so that they're automatically secure-erased when deleted. Other operating systems require a tool such as "wipe" or "shred" to completely destroy the files. The "leftover" pad can be re-used for future communications. You can make the pad as large or as small as you wish, but it must be larger than the file you wish to encrypt, and it's up to all parties to keep their pads "in sync" with the others. I didn't say OTP was practical, it's just really good when implemented correctly.

I advocate keeping ALL sensitive files (the pad and cleartext) on a USB flash drive along with a secure-erase tool. If the risk of compromise exists, 5-10 seconds in a microwave will render it and all contents completely useless. Although USB flash drives are solid state, given the nature of their construction, it's been proven that some information may be retrievable from them even after a secure erase. Always use your head.

Now that the formalities are out of the way, let's get started!

First, I created a 5kB file of pseudo-random data to use for my pad, and made a copy of the pad for the recipient.

Chimera:~/test ax0n$ dd if=/dev/urandom of=pad bs=1k count=5
5+0 records in
5+0 records out
5120 bytes transferred in 0.001332 secs (3843715 bytes/sec)

Chimera:~/test ax0n$ cp pad receiver-pad
Next, I launched my script. It requires 4 pieces of information. The pad file, the file to encrypt or decrypt, the output file, and the file to write the leftover portion of the pad to. After running it, you can see the script, the leftover pad, the original pad (which should be secure-erased immediately after use), the encrypted target file (in this case, my /etc/passwd file) and the pristine copy of the original pad which should have been handed (never transmitted!) to my recipient.
Chimera:~/test ax0n$ ./crypt.lsp pad /etc/passwd passwd.crypt leftover-pad

Chimera:~/test ax0n$ ls -la
total 56
drwxr-xr-x 7 ax0n ax0n 238 Feb 7 22:36 .
drwx------ 55 ax0n ax0n 1870 Feb 7 22:33 ..
-rwxr-xr-x 1 ax0n ax0n 675 Feb 7 22:33 crypt.lsp
-rw-r--r-- 1 ax0n ax0n 3188 Feb 7 22:36 leftover-pad
-rw-r--r-- 1 ax0n ax0n 5120 Feb 7 22:36 pad
-rw-r--r-- 1 ax0n ax0n 1932 Feb 7 22:36 passwd.crypt
-rw-r--r-- 1 ax0n ax0n 5120 Feb 7 22:36 receiver-pad
Here's part of the hexdump from the encrypted password file. It's very, very random.
Chimera:~/test ax0n$ hexdump -C passwd.crypt
00000000 d3 17 89 23 2f 51 bc 9c c2 3d d3 b3 fb e0 5c 4b |...#/Q...=....\K|
00000010 43 8e 4f e7 71 53 c7 fd 2b b2 ff 37 32 64 3a 2d |C.O.qS..+..72d:-|
00000020 df 8e 19 fa 64 07 c9 8d f2 36 f0 41 e6 ca 65 67 |....d....6.A..eg|
00000030 a3 a4 e6 b0 dc 48 14 08 12 0d c4 72 1a 18 c6 bc |.....H.....r....|
00000040 0a cd 79 69 2b f2 62 15 63 48 da f5 3d 36 41 e8 |..yi+.b.cH..=6A.|

...

00000730 4c 71 17 04 13 50 d2 e0 ab 3a 2d 44 16 0d 72 cf |Lq...P...:-D..r.|
00000740 60 47 16 43 8a 1f 73 03 e8 e9 b8 71 d6 ee fd 68 |`G.C..s....q...h|
00000750 09 dd 81 60 35 65 0b 8f 66 03 97 f4 96 39 78 44 |...`5e..f....9xD|
00000760 f8 24 99 bc 68 6e 28 14 f3 2f fc 0a a3 68 47 70 |.$..hn(../...hGp|
00000770 fd 41 fc 51 e2 c2 0c de 07 be 40 ce 6c a8 bb 5b |.A.Q......@.l..[|
00000780 88 4b 52 50 a4 95 b5 37 71 12 12 76 |.KRP...7q..v|
On the receiving end, we use the receiver-pad file against the encrypted password file, then we can see the new files with ls.
Chimera:~/test ax0n$ ./crypt.lsp receiver-pad  passwd.crypt passwd.clear reciever-leftover-pad

Chimera:~/test ax0n$ ls -la
total 72
drwxr-xr-x 9 ax0n ax0n 306 Feb 7 22:38 .
drwx------ 55 ax0n ax0n 1870 Feb 7 22:33 ..
-rwxr-xr-x 1 ax0n ax0n 675 Feb 7 22:33 crypt.lsp
-rw-r--r-- 1 ax0n ax0n 3188 Feb 7 22:36 leftover-pad
-rw-r--r-- 1 ax0n ax0n 5120 Feb 7 22:36 pad
-rw-r--r-- 1 ax0n ax0n 1932 Feb 7 22:38 passwd.clear
-rw-r--r-- 1 ax0n ax0n 1932 Feb 7 22:36 passwd.crypt
-rw-r--r-- 1 ax0n ax0n 3188 Feb 7 22:38 receiver-leftover-pad
-rw-r--r-- 1 ax0n ax0n 5120 Feb 7 22:36 receiver-pad


Let's see if the decrypted file is legible...


Chimera:~/test ax0n$ cat passwd.clear
##
# User Database
#
# Note that this file is consulted when the system is running in single-user
# mode. At other times this information is handled by one or more of:
# lookupd DirectoryServices
# By default, lookupd gets information from NetInfo, so this file will
# not be consulted unless you have changed lookupd's configuration.
# This file is used while in single user mode.
#
# To use this file for normal authentication, you may enable it with
# /Applications/Utilities/Directory Access.
##
nobody:*:-2:-2:Unprivileged User:/:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false

...

tokend:*:91:91:Token Daemon:/var/empty:/usr/bin/false
securityagent:*:92:92:SecurityAgent:/var/empty:/usr/bin/false
unknown:*:99:99:Unknown User:/var/empty:/usr/bin/false

Yep, it worked!

Let's look at the newLISP code for this project. On the newLISP discussion boards, cormullion and Lutz (the founder of newLISP) reminded me of the beauty of the "cond" command, which works a little bit like "case" except it evaluates whole expressions, not just one variable. I added a bit of whitespace into the code to show how "cond" works. They also helped me re-factor my argument assignment statements down to one line with "map".

#!/usr/bin/newlisp
(cond(
(< (length (main-args)) 5)
(println "USAGE: crypt.lsp [pad] [file] [output] [pad-remainder]")
)
(true
(map set '(pad target output remainder) (rest (rest (main-args))))
(write-file output (encrypt (read-file target) (read-file pad)))
(write-file remainder (slice (read-file pad) (length (read-file target))))
)
)
(exit)


Instead of taking the painstaking route of stepping through all the logic to show how XOR encryption works like I did in my cryptography example a few days ago, I am using as many newLISP shortcuts as I know how to while maintaining the feature set I want. For instance, newLISP has the "encrypt" function which is exactly what I was using in my original example. It runs a bitwise XOR of the contents of two variables, even if those variables contain the entire contents of files! There's no need to explode strings, map the char command, or anything like that. In the above example, newLISP essentially handles all the core logic in this single line:

(write-file output (encrypt (read-file target) (read-file pad)))

It single-handedly reads the pad and target file, XORs them with the encrypt function and writes the resulting garble to the output file.

The line below it figures the length of the target file, skips over that many bytes of the pad file and writes the remaining bytes in the pad out to the remainder file.

Look for more articles like this as I keep playing with newLISP and learning more about it.

Wednesday, February 7, 2007

Cryptography fun with newLISP

Some of you may have seen my article in the latest 2600 magazine about newLISP, a very fast scripting language based on LISP.

Well, the HiR crew has, for the better part of a year, been kicking around cryptography concepts. We keep coming back to one-time pad cryptography. It's fascinating in its simplicity. It's so computationally trivial that a human can quickly encrypt or decrypt a simple modular addition one-time pad scheme with nothing but a pencil and paper. The other thing is that, when implemented properly, OTP is perfectly secret and highly resistant to all forms of cryptanalysis. To this day, OTP is one of the most powerful and feared crypto schemes in existance.

Back here in computer world, we do a comparison on two numeric values assigned to the "cleartext" message. Since all ASCII characters have a decimal value in an 8-bit character space (256 distinct combinations), it's very easy to perform a bitwise Exclusive Or (XOR) on the cleartext and the key. XOR is simply "one or the other but not both". Let's try a cleartext of the letter A (binary 01000001) XOR against a key of "q" (binary 01110001). Comparing the bits vertically, the result will only have a "1" wherever either A or q have a differing bit at that location, but will have a "0" wherever both bits are the same.

"A"=01000001
"q"=01110001
-----00110000 (as it turns out, this is an ASCII uppercase "O")

newLISP, like all LISP based languages, handles lists and symbols very well. I just played around with this concept on the newLISP command line, and the result was fun, but not very practical as executed. I'll discuss ways to make this tinkering session a little more practical at the end of the article.

Ideally, the key would not be a string, but a very solid random set of characters known by the parties who are encrypting messages to one another. This doesn't even need to be a string, it may be binary random data...

A few things about this code. First, I'm a newbie at newLISP. Let me describe how some of this stuff works. The "explode" command turns a string variable into a list of characters. "char" turns a character into its ASCII decimal equivalent, or an ASCII decimal number back into a character. "map" simply takes the operation (such as "char") and uses that operation on a list. So (map char (explode cleartext)) would return the output of "char" for each individual character in the contents of the "cleartext" variable. Confusing enough? Okay, awesome!




newLISP code that I type will be in bold, red italics.
newLISP output will be in bold.
My comments will be in italics.


# newlisp
newLISP v.9.0 on OSX UTF-8, execute 'newlisp -h' for more info.

#first, I'll assign a key and convert it to a list of ascii numbers.
> (set 'key "Pa5$w0rd!")
"Pa5$w0rd!"

> (set 'kcharlist (map char (explode key)))
(80 97 53 36 119 48 114 100 33)

#Then, I'll assign a cleartext string and convert it to a list of ascii numbers as well.
> (set 'cleartext "HiR ownz.")
"HiR ownz."

> (set 'ccharlist (map char (explode cleartext)))
(72 105 82 32 111 119 110 122 46)

#In many languages, newLISP included, the carat "^" is the symbol for XOR. This line outputs the XOR values for each character compared between the cleartext and key)
> (set 'cryptcharlist (map ^ ccharlist kcharlist))
(24 8 103 4 24 71 28 30 15)

#Note that some of the characters from the XOR operation are non-printable, so their ASCII string notation /nnn is used instead.
> (set 'cryptostring (join (map char cryptcharlist)))
"\024\008g\004\024G\028\030\015"

#Now on the receiving end, we take the known key character list and we XOR the crypto character list. In reality we'd have to generate these again but we'd already set the variables above. No sense repeating the process here.
> (set 'decryptcharlist (map ^ cryptcharlist kcharlist))
(72 105 82 32 111 119 110 122 46)

#Finally, we take that string of numbers and join them after converting them from ASCII Decimal to characters again.
> (set 'decryptstring (join (map char decryptcharlist)))
"HiR ownz."


Now, as I'd mentioned before, in order to be really practical, you'd need an actual one-time pad that was very random. What I made above was a variant of Vernam cipher to give you a taste of how simple XOR based encryption is, not a genuine one-time pad. A few things that would make the above more practical:
  • A lot of the steps could have been consolidated. I broke it down to show how things worked. I could have simply put all of the logic in one line, but it would have been confusing.
  • The key and cleartext should be able to be read from a file. As implemented above, this should work with binary data (executables, images, etc) and with a very random binary key (pad) file.
  • In the code above, the key needs to be the exact same number of characters as the cleartext. If implemented practically, the program should read the length of the cleartext and use that many bytes of the random pad.
  • In a true one-time pad scheme, the sender and recipient both possess the same random key data, but the sender must destroy the part of the key that was used as soon as the encryption is performed. That way, only the recipient(s) may decrypt the message, as they have the only existing copy of the key. In turn, the recipient must destroy the part of the key used to decrypt the message so that in the event the encrypted message was compromised, there is no existing copy of the key available to aid in decryption.
  • The above inconveniences have been the main downfall to widespread use of OTP.
  • OTP's strength relies heavily on protocol, not technology.
As I get more free time, I will write a quick one-time pad newLISP script that can do most of the above things. I just got the craving to tinker and write a little bit, and thought I'd share it here.

--Ax0n