diff options
Diffstat (limited to 'infrastructure/net.appjet.oui/encryption.scala')
-rw-r--r-- | infrastructure/net.appjet.oui/encryption.scala | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/infrastructure/net.appjet.oui/encryption.scala b/infrastructure/net.appjet.oui/encryption.scala new file mode 100644 index 0000000..92d463b --- /dev/null +++ b/infrastructure/net.appjet.oui/encryption.scala @@ -0,0 +1,267 @@ +/** + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.appjet.oui; + +import scala.collection.mutable.ArrayBuffer; + +import javax.crypto.Cipher; +import java.security._; +import java.security.spec._; +import java.math.BigInteger; +import java.io.{ObjectInputStream, ObjectOutputStream, FileInputStream, FileOutputStream, PrintWriter, OutputStreamWriter, ByteArrayOutputStream, ByteArrayInputStream, InputStream, InputStreamReader, BufferedReader, DataOutputStream, DataInputStream}; + +import net.appjet.common.util.BetterFile; + +// object EncryptomaticTest { +// def main(args: Array[String]) { +// args(0) match { +// case "genkeys" => { +// val keyPair = Encryptomatic.generateKeyPair; +// println("made key pair.") +// Encryptomatic.writeKeyPair(keyPair, args(1), args(2)); +// println("done."); +// } +// case "printkeys" => { +// val keyPair = Encryptomatic.generateKeyPair; +// val Pair(pubBytes, privBytes) = Encryptomatic.keyPairBytes(keyPair); +// println("Public key: "+Encryptomatic.bytesToAscii(pubBytes)) +// println("Private key: "+Encryptomatic.bytesToAscii(privBytes)); +// } +// case "sign" => { +// println(Encryptomatic.sign(java.lang.System.in, Encryptomatic.readPrivateKey(new FileInputStream(args(1))))); +// } +// case "verify" => { +// if (Encryptomatic.verify(java.lang.System.in, Encryptomatic.readPublicKey(new FileInputStream(args(1))), args(2))) { +// println("Verification succeeded."); +// } else { +// println("Verification failed."); +// } +// } +// case "test" => { +// val out = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"), true); +// val src = "Hey dudes, this is a test of この魚は築地からのですか?"; +// out.println(src); +// val bytes = Encryptomatic.bytesToAscii(src.getBytes("UTF-8")); +// out.println("bytes: "+bytes); +// val done = new String(Encryptomatic.asciiToBytes(bytes), "UTF-8"); +// out.println(done); +// out.println("Match? "+(done == src)); +// } +// case "keytest" => { +// val keyPair = Encryptomatic.generateKeyPair; +// val bytes = Encryptomatic.keyPairBytes(keyPair); +// try { +// val newKeyPair = Encryptomatic.readKeyPair(new ByteArrayInputStream(Encryptomatic.bytesToAscii(bytes._1).getBytes()), +// new ByteArrayInputStream(Encryptomatic.bytesToAscii(bytes._2).getBytes())); +// println("equal? "+(keyPair.getPublic.getEncoded.deepEquals(newKeyPair.getPublic.getEncoded) && keyPair.getPrivate.getEncoded.deepEquals(newKeyPair.getPrivate.getEncoded))); +// } catch { +// case e: InvalidKeySpecException => { +// println("equality failed.") +// println("public key 1 is: "+bytes._1.mkString("(", ",", ")")); +// println("public key 2 is: "+BetterFile.getStreamBytes(new Encryptomatic.AsciiToBytesInputStream(new ByteArrayInputStream(Encryptomatic.bytesToAscii(bytes._1).getBytes()))).mkString("(", ",", ")")); +// println("pk1 enc to: "+Encryptomatic.bytesToAscii(bytes._1)); +// } +// } +// } +// } +// } +// } + +object Encryptomatic { + private val chars = "0123456789abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + def bytesToAscii(bytes: Array[Byte]) = { + var i = BigInt(bytes); + val neg = i < 0; + if (neg) + i = BigInt(0)-i; + val sb = new StringBuffer(); + while (i > BigInt(chars.length-1)) { + val Pair(div, mod) = i /% BigInt(chars.length); + sb.append(chars(mod.intValue)); + i = div; + } + sb.append(chars(i.intValue)); + (if (neg) "-" else "")+sb.toString.reverse; + } + def asciiToBytes(src: String) = { + var i = BigInt(0); + val Pair(isNegative, b) = + if (src.startsWith("-")) + (true, src.substring(1)) + else + (false, src); + for (c <- b) { + i = i * chars.length + chars.indexOf(c); + } + if (isNegative) + i = BigInt(0)-i; + i.toByteArray + } + + def generateKeyPair(keyType: String) = { + val keyGen = KeyPairGenerator.getInstance(keyType); + val random = SecureRandom.getInstance("SHA1PRNG", "SUN"); + keyGen.initialize(1024, random); + keyGen.generateKeyPair(); + } + + def keyPairBytes(keyPair: KeyPair) = { + val pubKey = keyPair.getPublic(); + if (pubKey.getFormat != "X.509") + throw new RuntimeException("Can't produce public key in format: "+pubKey.getFormat); + + val privKey = keyPair.getPrivate(); + if (privKey.getFormat != "PKCS#8") + throw new RuntimeException("Can't produce private key in format: "+privKey.getFormat); + + (pubKey.getEncoded, privKey.getEncoded) + } + + def writeKeyPair(keyPair: KeyPair, publicKey: String, privateKey: String) { + val pubOutputStream = new PrintWriter(new FileOutputStream(publicKey)); + val privOutputStream = new PrintWriter(new FileOutputStream(privateKey)); + val Pair(pubBytes, privBytes) = keyPairBytes(keyPair); + pubOutputStream.print(bytesToAscii(pubBytes)); + privOutputStream.print(bytesToAscii(privBytes)); + List(pubOutputStream, privOutputStream).foreach(x => {x.flush(); x.close()}); + } + + class AsciiToBytesInputStream(in: InputStream) extends InputStream { + val reader = new BufferedReader(new InputStreamReader(in)); + val bytes = new ByteArrayInputStream(asciiToBytes(reader.readLine())); + def read(): Int = bytes.read(); + } + + def readPublicKey(keyType: String, publicKey: InputStream) = { + val pubKeySpec = new X509EncodedKeySpec(BetterFile.getStreamBytes(new AsciiToBytesInputStream(publicKey))); + KeyFactory.getInstance(keyType).generatePublic(pubKeySpec); + } + def readPrivateKey(keyType: String, privateKey: InputStream) = { + val privKeySpec = new PKCS8EncodedKeySpec(BetterFile.getStreamBytes(new AsciiToBytesInputStream(privateKey))); + KeyFactory.getInstance(keyType).generatePrivate(privKeySpec); + } + + def readKeyPair(keyType: String, publicKey: InputStream, privateKey: InputStream) = { + new KeyPair(readPublicKey(keyType, publicKey), + readPrivateKey(keyType, privateKey)); + } + + def sign(source: InputStream, key: PrivateKey): Array[byte] = { + val dsa = Signature.getInstance("SHA1withDSA"); + dsa.initSign(key); + val inBytes = new Array[Byte](4096); + var count = source.read(inBytes); + while (count > 0) { + dsa.update(inBytes, 0, count); + count = source.read(inBytes); + } + dsa.sign(); + } + + def verify(source: InputStream, key: PublicKey, sig: Array[byte]): Boolean = { + val dsa = Signature.getInstance("SHA1withDSA"); + dsa.initVerify(key); + val inBytes = new Array[Byte](4096); + var count = source.read(inBytes); + while (count > 0) { + dsa.update(inBytes, 0, count); + count = source.read(inBytes); + } + dsa.verify(sig) + } + + def encrypt(source: InputStream, key: PublicKey): Array[byte] = { + val cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, key); + val inBytes = new Array[Byte](100); + val outBytesStream = new ByteArrayOutputStream(); + val dataOut = new DataOutputStream(outBytesStream); + + var count = source.read(inBytes); + while (count > 0) { + val arr = cipher.doFinal(inBytes, 0, count); + dataOut.writeShort(arr.length); + dataOut.write(arr, 0, arr.length); + count = source.read(inBytes); + } + dataOut.writeShort(0); + outBytesStream.toByteArray(); + } + + def decrypt(source: InputStream, key: PrivateKey): Array[byte] = { + val in = new DataInputStream(source); + def readBlock() = { + val length = in.readShort(); + if (length > 0) { + val bytes = new Array[Byte](length); + in.readFully(bytes); + Some(bytes); + } else { + None; + } + } + val outBytes = new ArrayBuffer[Byte]; + val cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, key); + var block = readBlock(); + while (block.isDefined) { + outBytes ++= cipher.doFinal(block.get); + block = readBlock(); + } + outBytes.toArray; + } +} + +object Encryptor { + def main(args: Array[String]) { + args(0) match { + case "genkeys" => { + println("generating keys..."); + val keyPair = Encryptomatic.generateKeyPair(args(1)); + println("saving public key to: "+args(2)+"; private key to: "+args(3)); + Encryptomatic.writeKeyPair(keyPair, args(2), args(3)); + println("done."); + } + case "test" => { + val plaintext = "This is a test of some data that's actually pretty long once you really start thinking about it. I mean, it needs to be more than 117 bytes for it to be a reasonable test, and I suppose it's pretty close to that now. OK, let's just go for it and see what happens.".getBytes("UTF-8"); + val keys = Encryptomatic.generateKeyPair("RSA"); + val ciphertext = Encryptomatic.bytesToAscii(Encryptomatic.encrypt(new ByteArrayInputStream(plaintext), keys.getPublic())); + println(ciphertext); + println(new String(Encryptomatic.decrypt(new ByteArrayInputStream(Encryptomatic.asciiToBytes(ciphertext)), keys.getPrivate()), "UTF-8")); + } + case "decode" => { + val key = Encryptomatic.readPrivateKey(args(1), new FileInputStream(args(2))); + val plaintext = Encryptomatic.decrypt(new ByteArrayInputStream(Encryptomatic.asciiToBytes(args(3))), key); + println(new String(plaintext, "UTF-8")); + } + case "decodeFile" => { + println("Enter private key (assuming type RSA):"); + val key = Encryptomatic.readPrivateKey("RSA", java.lang.System.in); + val file = new java.io.File(args(1)); + println("Reading "+file.getName()+"..."); + val reader = new java.io.BufferedReader(new java.io.InputStreamReader(new FileInputStream(file))); + var line = reader.readLine(); + while (line != null) { + val bytes = Encryptomatic.decrypt(new ByteArrayInputStream(Encryptomatic.asciiToBytes(line)), key); + println(new String(bytes, "UTF-8")); + line = reader.readLine(); + } + } + } + } +} |