2
copyrev: abefe5a4f16a02143acacdc38970f02e8c59e38b
3
copy: trunk/trunk/infrastructure/net.appjet.oui/encryption.scala
6
* Copyright 2009 Google Inc.
8
* Licensed under the Apache License, Version 2.0 (the "License");
9
* you may not use this file except in compliance with the License.
10
* You may obtain a copy of the License at
12
* http://www.apache.org/licenses/LICENSE-2.0
14
* Unless required by applicable law or agreed to in writing, software
15
* distributed under the License is distributed on an "AS-IS" BASIS,
16
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
* See the License for the specific language governing permissions and
18
* limitations under the License.
21
package net.appjet.oui;
23
import scala.collection.mutable.ArrayBuffer;
25
import javax.crypto.Cipher;
26
import java.security._;
27
import java.security.spec._;
28
import java.math.BigInteger;
29
import java.io.{ObjectInputStream, ObjectOutputStream, FileInputStream, FileOutputStream, PrintWriter, OutputStreamWriter, ByteArrayOutputStream, ByteArrayInputStream, InputStream, InputStreamReader, BufferedReader, DataOutputStream, DataInputStream};
31
import net.appjet.common.util.BetterFile;
33
// object EncryptomaticTest {
34
// def main(args: Array[String]) {
36
// case "genkeys" => {
37
// val keyPair = Encryptomatic.generateKeyPair;
38
// println("made key pair.")
39
// Encryptomatic.writeKeyPair(keyPair, args(1), args(2));
42
// case "printkeys" => {
43
// val keyPair = Encryptomatic.generateKeyPair;
44
// val Pair(pubBytes, privBytes) = Encryptomatic.keyPairBytes(keyPair);
45
// println("Public key: "+Encryptomatic.bytesToAscii(pubBytes))
46
// println("Private key: "+Encryptomatic.bytesToAscii(privBytes));
49
// println(Encryptomatic.sign(java.lang.System.in, Encryptomatic.readPrivateKey(new FileInputStream(args(1)))));
52
// if (Encryptomatic.verify(java.lang.System.in, Encryptomatic.readPublicKey(new FileInputStream(args(1))), args(2))) {
53
// println("Verification succeeded.");
55
// println("Verification failed.");
59
// val out = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"), true);
60
// val src = "Hey dudes, this is a test of この魚は築地からのですか?";
62
// val bytes = Encryptomatic.bytesToAscii(src.getBytes("UTF-8"));
63
// out.println("bytes: "+bytes);
64
// val done = new String(Encryptomatic.asciiToBytes(bytes), "UTF-8");
66
// out.println("Match? "+(done == src));
68
// case "keytest" => {
69
// val keyPair = Encryptomatic.generateKeyPair;
70
// val bytes = Encryptomatic.keyPairBytes(keyPair);
72
// val newKeyPair = Encryptomatic.readKeyPair(new ByteArrayInputStream(Encryptomatic.bytesToAscii(bytes._1).getBytes()),
73
// new ByteArrayInputStream(Encryptomatic.bytesToAscii(bytes._2).getBytes()));
74
// println("equal? "+(keyPair.getPublic.getEncoded.deepEquals(newKeyPair.getPublic.getEncoded) && keyPair.getPrivate.getEncoded.deepEquals(newKeyPair.getPrivate.getEncoded)));
76
// case e: InvalidKeySpecException => {
77
// println("equality failed.")
78
// println("public key 1 is: "+bytes._1.mkString("(", ",", ")"));
79
// println("public key 2 is: "+BetterFile.getStreamBytes(new Encryptomatic.AsciiToBytesInputStream(new ByteArrayInputStream(Encryptomatic.bytesToAscii(bytes._1).getBytes()))).mkString("(", ",", ")"));
80
// println("pk1 enc to: "+Encryptomatic.bytesToAscii(bytes._1));
88
object Encryptomatic {
89
private val chars = "0123456789abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
91
def bytesToAscii(bytes: Array[Byte]) = {
92
var i = BigInt(bytes);
96
val sb = new StringBuffer();
97
while (i > BigInt(chars.length-1)) {
98
val Pair(div, mod) = i /% BigInt(chars.length);
99
sb.append(chars(mod.intValue));
102
sb.append(chars(i.intValue));
103
(if (neg) "-" else "")+sb.toString.reverse;
105
def asciiToBytes(src: String) = {
107
val Pair(isNegative, b) =
108
if (src.startsWith("-"))
109
(true, src.substring(1))
113
i = i * chars.length + chars.indexOf(c);
120
def generateKeyPair(keyType: String) = {
121
val keyGen = KeyPairGenerator.getInstance(keyType);
122
val random = SecureRandom.getInstance("SHA1PRNG", "SUN");
123
keyGen.initialize(1024, random);
124
keyGen.generateKeyPair();
127
def keyPairBytes(keyPair: KeyPair) = {
128
val pubKey = keyPair.getPublic();
129
if (pubKey.getFormat != "X.509")
130
throw new RuntimeException("Can't produce public key in format: "+pubKey.getFormat);
132
val privKey = keyPair.getPrivate();
133
if (privKey.getFormat != "PKCS#8")
134
throw new RuntimeException("Can't produce private key in format: "+privKey.getFormat);
136
(pubKey.getEncoded, privKey.getEncoded)
139
def writeKeyPair(keyPair: KeyPair, publicKey: String, privateKey: String) {
140
val pubOutputStream = new PrintWriter(new FileOutputStream(publicKey));
141
val privOutputStream = new PrintWriter(new FileOutputStream(privateKey));
142
val Pair(pubBytes, privBytes) = keyPairBytes(keyPair);
143
pubOutputStream.print(bytesToAscii(pubBytes));
144
privOutputStream.print(bytesToAscii(privBytes));
145
List(pubOutputStream, privOutputStream).foreach(x => {x.flush(); x.close()});
148
class AsciiToBytesInputStream(in: InputStream) extends InputStream {
149
val reader = new BufferedReader(new InputStreamReader(in));
150
val bytes = new ByteArrayInputStream(asciiToBytes(reader.readLine()));
151
def read(): Int = bytes.read();
154
def readPublicKey(keyType: String, publicKey: InputStream) = {
155
val pubKeySpec = new X509EncodedKeySpec(BetterFile.getStreamBytes(new AsciiToBytesInputStream(publicKey)));
156
KeyFactory.getInstance(keyType).generatePublic(pubKeySpec);
158
def readPrivateKey(keyType: String, privateKey: InputStream) = {
159
val privKeySpec = new PKCS8EncodedKeySpec(BetterFile.getStreamBytes(new AsciiToBytesInputStream(privateKey)));
160
KeyFactory.getInstance(keyType).generatePrivate(privKeySpec);
163
def readKeyPair(keyType: String, publicKey: InputStream, privateKey: InputStream) = {
164
new KeyPair(readPublicKey(keyType, publicKey),
165
readPrivateKey(keyType, privateKey));
168
def sign(source: InputStream, key: PrivateKey): Array[byte] = {
169
val dsa = Signature.getInstance("SHA1withDSA");
171
val inBytes = new Array[Byte](4096);
172
var count = source.read(inBytes);
174
dsa.update(inBytes, 0, count);
175
count = source.read(inBytes);
180
def verify(source: InputStream, key: PublicKey, sig: Array[byte]): Boolean = {
181
val dsa = Signature.getInstance("SHA1withDSA");
183
val inBytes = new Array[Byte](4096);
184
var count = source.read(inBytes);
186
dsa.update(inBytes, 0, count);
187
count = source.read(inBytes);
192
def encrypt(source: InputStream, key: PublicKey): Array[byte] = {
193
val cipher = Cipher.getInstance("RSA");
194
cipher.init(Cipher.ENCRYPT_MODE, key);
195
val inBytes = new Array[Byte](100);
196
val outBytesStream = new ByteArrayOutputStream();
197
val dataOut = new DataOutputStream(outBytesStream);
199
var count = source.read(inBytes);
201
val arr = cipher.doFinal(inBytes, 0, count);
202
dataOut.writeShort(arr.length);
203
dataOut.write(arr, 0, arr.length);
204
count = source.read(inBytes);
206
dataOut.writeShort(0);
207
outBytesStream.toByteArray();
210
def decrypt(source: InputStream, key: PrivateKey): Array[byte] = {
211
val in = new DataInputStream(source);
213
val length = in.readShort();
215
val bytes = new Array[Byte](length);
222
val outBytes = new ArrayBuffer[Byte];
223
val cipher = Cipher.getInstance("RSA");
224
cipher.init(Cipher.DECRYPT_MODE, key);
225
var block = readBlock();
226
while (block.isDefined) {
227
outBytes ++= cipher.doFinal(block.get);
235
def main(args: Array[String]) {
238
println("generating keys...");
239
val keyPair = Encryptomatic.generateKeyPair(args(1));
240
println("saving public key to: "+args(2)+"; private key to: "+args(3));
241
Encryptomatic.writeKeyPair(keyPair, args(2), args(3));
245
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");
246
val keys = Encryptomatic.generateKeyPair("RSA");
247
val ciphertext = Encryptomatic.bytesToAscii(Encryptomatic.encrypt(new ByteArrayInputStream(plaintext), keys.getPublic()));
249
println(new String(Encryptomatic.decrypt(new ByteArrayInputStream(Encryptomatic.asciiToBytes(ciphertext)), keys.getPrivate()), "UTF-8"));
252
val key = Encryptomatic.readPrivateKey(args(1), new FileInputStream(args(2)));
253
val plaintext = Encryptomatic.decrypt(new ByteArrayInputStream(Encryptomatic.asciiToBytes(args(3))), key);
254
println(new String(plaintext, "UTF-8"));
256
case "decodeFile" => {
257
println("Enter private key (assuming type RSA):");
258
val key = Encryptomatic.readPrivateKey("RSA", java.lang.System.in);
259
val file = new java.io.File(args(1));
260
println("Reading "+file.getName()+"...");
261
val reader = new java.io.BufferedReader(new java.io.InputStreamReader(new FileInputStream(file)));
262
var line = reader.readLine();
263
while (line != null) {
264
val bytes = Encryptomatic.decrypt(new ByteArrayInputStream(Encryptomatic.asciiToBytes(line)), key);
265
println(new String(bytes, "UTF-8"));
266
line = reader.readLine();