~mrooney/etherpad/ubuntu

« back to all changes in this revision

Viewing changes to trunk/infrastructure/net.appjet.oui/encryption.scala

  • Committer: Aaron Iba
  • Date: 2009-12-18 07:44:23 UTC
  • Revision ID: hg-v1:81287c8af1ac7133316fd4416b13a64c9faba321
removed duplicate trunk directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1

 
2
copyrev: abefe5a4f16a02143acacdc38970f02e8c59e38b
 
3
copy: trunk/trunk/infrastructure/net.appjet.oui/encryption.scala
 
4

 
5
/**
 
6
 * Copyright 2009 Google Inc.
 
7
 * 
 
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
 
11
 * 
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 * 
 
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.
 
19
 */
 
20
 
 
21
package net.appjet.oui;
 
22
 
 
23
import scala.collection.mutable.ArrayBuffer;
 
24
 
 
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};
 
30
 
 
31
import net.appjet.common.util.BetterFile;
 
32
 
 
33
// object EncryptomaticTest {
 
34
//   def main(args: Array[String]) {
 
35
//     args(0) match {
 
36
//       case "genkeys" => {
 
37
//      val keyPair = Encryptomatic.generateKeyPair;
 
38
//      println("made key pair.")
 
39
//      Encryptomatic.writeKeyPair(keyPair, args(1), args(2));
 
40
//      println("done.");
 
41
//       }
 
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));
 
47
//       }
 
48
//       case "sign" => {
 
49
//      println(Encryptomatic.sign(java.lang.System.in, Encryptomatic.readPrivateKey(new FileInputStream(args(1)))));
 
50
//       }
 
51
//       case "verify" => {
 
52
//      if (Encryptomatic.verify(java.lang.System.in, Encryptomatic.readPublicKey(new FileInputStream(args(1))), args(2))) {
 
53
//        println("Verification succeeded.");
 
54
//      } else {
 
55
//        println("Verification failed.");
 
56
//      }
 
57
//       }
 
58
//       case "test" => {
 
59
//      val out = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"), true);
 
60
//      val src = "Hey dudes, this is a test of この魚は築地からのですか?";
 
61
//      out.println(src);
 
62
//      val bytes = Encryptomatic.bytesToAscii(src.getBytes("UTF-8"));
 
63
//      out.println("bytes: "+bytes);
 
64
//      val done = new String(Encryptomatic.asciiToBytes(bytes), "UTF-8");
 
65
//      out.println(done);
 
66
//      out.println("Match? "+(done == src));
 
67
//       }
 
68
//       case "keytest" => {
 
69
//      val keyPair = Encryptomatic.generateKeyPair;
 
70
//      val bytes = Encryptomatic.keyPairBytes(keyPair);
 
71
//      try { 
 
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)));
 
75
//      } catch {
 
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));
 
81
//        }
 
82
//      }
 
83
//       }
 
84
//     }
 
85
//   }
 
86
// }
 
87
 
 
88
object Encryptomatic {
 
89
  private val chars = "0123456789abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
90
 
 
91
  def bytesToAscii(bytes: Array[Byte]) = {
 
92
    var i = BigInt(bytes);
 
93
    val neg = i < 0;
 
94
    if (neg)
 
95
      i = BigInt(0)-i;
 
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));
 
100
      i = div;
 
101
    }
 
102
    sb.append(chars(i.intValue));
 
103
    (if (neg) "-" else "")+sb.toString.reverse;
 
104
  }
 
105
  def asciiToBytes(src: String) = {
 
106
    var i = BigInt(0);
 
107
    val Pair(isNegative, b) = 
 
108
      if (src.startsWith("-"))
 
109
        (true, src.substring(1))
 
110
      else
 
111
        (false, src);
 
112
    for (c <- b) {
 
113
      i = i * chars.length + chars.indexOf(c);
 
114
    }
 
115
    if (isNegative)
 
116
      i = BigInt(0)-i;
 
117
    i.toByteArray
 
118
  }
 
119
 
 
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();
 
125
  }
 
126
 
 
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);
 
131
 
 
132
    val privKey = keyPair.getPrivate();
 
133
    if (privKey.getFormat != "PKCS#8")
 
134
      throw new RuntimeException("Can't produce private key in format: "+privKey.getFormat);
 
135
 
 
136
    (pubKey.getEncoded, privKey.getEncoded)
 
137
  }
 
138
 
 
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()});
 
146
  }
 
147
 
 
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();
 
152
  }
 
153
  
 
154
  def readPublicKey(keyType: String, publicKey: InputStream) = {
 
155
    val pubKeySpec = new X509EncodedKeySpec(BetterFile.getStreamBytes(new AsciiToBytesInputStream(publicKey)));
 
156
    KeyFactory.getInstance(keyType).generatePublic(pubKeySpec);
 
157
  }
 
158
  def readPrivateKey(keyType: String, privateKey: InputStream) = {
 
159
    val privKeySpec = new PKCS8EncodedKeySpec(BetterFile.getStreamBytes(new AsciiToBytesInputStream(privateKey)));    
 
160
    KeyFactory.getInstance(keyType).generatePrivate(privKeySpec);
 
161
  }
 
162
 
 
163
  def readKeyPair(keyType: String, publicKey: InputStream, privateKey: InputStream) = {
 
164
    new KeyPair(readPublicKey(keyType, publicKey),
 
165
                readPrivateKey(keyType, privateKey));
 
166
  }  
 
167
 
 
168
  def sign(source: InputStream, key: PrivateKey): Array[byte] = {
 
169
    val dsa = Signature.getInstance("SHA1withDSA");
 
170
    dsa.initSign(key);
 
171
    val inBytes = new Array[Byte](4096);
 
172
    var count = source.read(inBytes);
 
173
    while (count > 0) {
 
174
      dsa.update(inBytes, 0, count);
 
175
      count = source.read(inBytes);
 
176
    }
 
177
    dsa.sign();
 
178
  }
 
179
 
 
180
  def verify(source: InputStream, key: PublicKey, sig: Array[byte]): Boolean = {
 
181
    val dsa = Signature.getInstance("SHA1withDSA");
 
182
    dsa.initVerify(key);
 
183
    val inBytes = new Array[Byte](4096);
 
184
    var count = source.read(inBytes);
 
185
    while (count > 0) {
 
186
      dsa.update(inBytes, 0, count);
 
187
      count = source.read(inBytes);
 
188
    }
 
189
    dsa.verify(sig)
 
190
  }
 
191
  
 
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);
 
198
 
 
199
    var count = source.read(inBytes);
 
200
    while (count > 0) {
 
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);
 
205
    }
 
206
    dataOut.writeShort(0);
 
207
    outBytesStream.toByteArray();
 
208
  }
 
209
  
 
210
  def decrypt(source: InputStream, key: PrivateKey): Array[byte] = {
 
211
    val in = new DataInputStream(source);
 
212
    def readBlock() = {
 
213
      val length = in.readShort();
 
214
      if (length > 0) {
 
215
        val bytes = new Array[Byte](length);
 
216
        in.readFully(bytes);
 
217
        Some(bytes);
 
218
      } else {
 
219
        None;
 
220
      }
 
221
    }
 
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);
 
228
      block = readBlock();
 
229
    }
 
230
    outBytes.toArray;
 
231
  }
 
232
}
 
233
 
 
234
object Encryptor {
 
235
  def main(args: Array[String]) {
 
236
    args(0) match {
 
237
      case "genkeys" => {
 
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));
 
242
        println("done.");
 
243
      }
 
244
      case "test" => {
 
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()));
 
248
        println(ciphertext);
 
249
        println(new String(Encryptomatic.decrypt(new ByteArrayInputStream(Encryptomatic.asciiToBytes(ciphertext)), keys.getPrivate()), "UTF-8"));
 
250
      }
 
251
      case "decode" => {
 
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"));
 
255
      }
 
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();
 
267
        }
 
268
      }
 
269
    }
 
270
  }
 
271
}