Download | Plain Text | No Line Numbers


  1. /*
  2.  * Copyright (c) 2010, Manuel Mausz. All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * - Redistributions of source code must retain the above copyright
  9.  * notice, this list of conditions and the following disclaimer.
  10.  *
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  * notice, this list of conditions and the following disclaimer in the
  13.  * documentation and/or other materials provided with the distribution.
  14.  *
  15.  * - The names of the authors may not be used to endorse or promote products
  16.  * derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  19.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  20.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. import java.io.*;
  32. import javax.crypto.*;
  33. import java.util.Collection;
  34. import java.util.Iterator;
  35. import org.bouncycastle.util.encoders.Base64;
  36. import java.security.GeneralSecurityException;
  37.  
  38. /*
  39.  * Common static methods used by all applications
  40.  *
  41.  * @author Manuel Mausz (0728348)
  42.  */
  43. class Utils
  44. {
  45. static class Shutdown
  46. extends java.lang.RuntimeException
  47. {
  48. public Shutdown()
  49. {
  50. super();
  51. }
  52.  
  53. public Shutdown(String message)
  54. {
  55. super(message);
  56. }
  57. }
  58.  
  59. /*==========================================================================*/
  60.  
  61. private static final String B64 = "a-zA-Z0-9/+";
  62.  
  63. /*==========================================================================*/
  64.  
  65. public static <T> String join(final Collection<T> objs, final String delimiter)
  66. {
  67. if (objs == null || objs.isEmpty())
  68. return "";
  69. Iterator<T> iter = objs.iterator();
  70. StringBuffer buffer = new StringBuffer(iter.next().toString());
  71. while (iter.hasNext())
  72. buffer.append(delimiter).append(iter.next().toString());
  73. return buffer.toString();
  74. }
  75.  
  76. /*--------------------------------------------------------------------------*/
  77.  
  78. public static long parseHeaderNum(String[] args, int index)
  79. {
  80. long num = -1;
  81. try
  82. {
  83. if (args.length < index + 1)
  84. throw new NumberFormatException();
  85. num = Long.parseLong(args[index]);
  86. if (num < 0)
  87. throw new NumberFormatException();
  88. }
  89. catch(NumberFormatException e)
  90. {
  91. System.err.println("Error: Invalid network paket from peer:");
  92. System.err.println(join(java.util.Arrays.asList(args), " "));
  93. }
  94. return num;
  95. }
  96.  
  97. /*------------------------------------------------------------------------*/
  98.  
  99. public static void sendOutput(EncObjectOutputStream out, String[] msgs)
  100. throws IOException
  101. {
  102. out.writeLine("!output " + msgs.length);
  103. for(String msg : msgs)
  104. out.writeLine("!" + msg);
  105. out.flush();
  106. }
  107.  
  108. /*------------------------------------------------------------------------*/
  109.  
  110. public static void sendOutput(EncObjectOutputStream out, String msg)
  111. throws IOException
  112. {
  113. String[] tmp = { msg };
  114. sendOutput(out, tmp);
  115. }
  116.  
  117. /*------------------------------------------------------------------------*/
  118.  
  119. public static void sendError(EncObjectOutputStream out, String[] msgs)
  120. throws IOException
  121. {
  122. out.writeLine("!error " + msgs.length);
  123. for(String msg : msgs)
  124. out.writeLine("!" + msg);
  125. out.flush();
  126. }
  127.  
  128. /*------------------------------------------------------------------------*/
  129.  
  130. public static void sendError(EncObjectOutputStream out, String msg)
  131. throws IOException
  132. {
  133. String[] tmp = { "Error: " + msg };
  134. sendError(out, tmp);
  135. }
  136.  
  137. /*==========================================================================*/
  138.  
  139. static class EncObjectInputStream
  140. extends ObjectInputStream
  141. {
  142. private Cipher cipher = null;
  143. private Mac mac = null;
  144.  
  145. public EncObjectInputStream(InputStream in)
  146. throws IOException
  147. {
  148. super(in);
  149. }
  150.  
  151. /*------------------------------------------------------------------------*/
  152.  
  153. public void setCipher(Cipher cipher)
  154. {
  155. this.cipher = cipher;
  156. }
  157.  
  158. /*------------------------------------------------------------------------*/
  159.  
  160. public void setMAC(Mac mac)
  161. {
  162. this.mac = mac;
  163. }
  164.  
  165. /*------------------------------------------------------------------------*/
  166.  
  167. private String decode(String msg)
  168. {
  169. if (msg == null)
  170. return null;
  171. if ((cipher == null && mac == null) || msg.charAt(0) == '!')
  172. return msg;
  173.  
  174. if (mac != null)
  175. {
  176. msg = new String(Base64.decode(msg));
  177. assert msg.matches("[" + B64 + "]{43}= [\\s[^\\s]]+");
  178. int ix = msg.indexOf(' ');
  179. if (ix == -1)
  180. {
  181. System.err.println("Error: invalid hashed message format:");
  182. System.err.println(msg);
  183. return null;
  184. }
  185. String hasht = msg.substring(0, ix);
  186. String msgtmp = msg.substring(ix + 1);
  187. String hashc = new String(Base64.encode(mac.doFinal(msgtmp.getBytes())));
  188. if (!hasht.equals(hashc))
  189. {
  190. System.err.println("Error: invalid MAC:");
  191. System.err.println(msg);
  192. throw new HashError();
  193. //return null;
  194. }
  195. msg = msgtmp;
  196. }
  197.  
  198. if (cipher != null)
  199. {
  200. try
  201. {
  202. byte[] decmsg = Base64.decode(msg);
  203. return new String(cipher.doFinal(decmsg));
  204. }
  205. catch(GeneralSecurityException e)
  206. {
  207. System.err.println("Error: Unable to decode message: " + e.getMessage());
  208. return null;
  209. }
  210. }
  211.  
  212. return msg;
  213. }
  214.  
  215. /*------------------------------------------------------------------------*/
  216.  
  217. public String readUTF()
  218. throws IOException
  219. {
  220. return decode(super.readUTF());
  221. }
  222.  
  223. /*------------------------------------------------------------------------*/
  224.  
  225. @SuppressWarnings("deprecation")
  226. public String readLine()
  227. throws IOException
  228. {
  229. return decode(super.readLine());
  230. }
  231. }
  232.  
  233. /*==========================================================================*/
  234.  
  235. static class EncObjectOutputStream
  236. extends ObjectOutputStream
  237. {
  238. private Cipher cipher = null;
  239. private Mac mac = null;
  240.  
  241. public EncObjectOutputStream(OutputStream out)
  242. throws IOException
  243. {
  244. super(out);
  245. }
  246.  
  247. /*------------------------------------------------------------------------*/
  248.  
  249. public void setCipher(Cipher cipher)
  250. {
  251. this.cipher = cipher;
  252. }
  253.  
  254. /*------------------------------------------------------------------------*/
  255.  
  256. public void setMAC(Mac mac)
  257. {
  258. this.mac = mac;
  259. }
  260.  
  261. /*------------------------------------------------------------------------*/
  262.  
  263. private byte[] encode(byte[] msg)
  264. {
  265. try
  266. {
  267. return Base64.encode(cipher.doFinal(msg));
  268. }
  269. catch(GeneralSecurityException e)
  270. {
  271. System.err.println("Error: Unable to encode message: " + e.getMessage());
  272. }
  273. return null;
  274. }
  275.  
  276. /*------------------------------------------------------------------------*/
  277.  
  278. public void writeUTF(String msg)
  279. throws IOException
  280. {
  281. if (cipher == null && mac == null)
  282. {
  283. super.writeUTF(msg);
  284. return;
  285. }
  286.  
  287. if (mac != null)
  288. {
  289. byte[] hash = mac.doFinal(msg.getBytes());
  290. msg = new String(Base64.encode(hash)) + " " + msg;
  291. assert msg.matches("[" + B64 + "]{43}= [\\s[^\\s]]+");
  292. }
  293.  
  294. if (cipher != null)
  295. {
  296. super.writeUTF(new String(encode(msg.getBytes())));
  297. return;
  298. }
  299.  
  300. String hashedmsg = new String(Base64.encode(msg.getBytes()));
  301. super.writeUTF(hashedmsg);
  302. return;
  303. }
  304.  
  305. /*------------------------------------------------------------------------*/
  306.  
  307. public void writeLine(String msg)
  308. throws IOException
  309. {
  310. if (cipher == null && mac == null)
  311. {
  312. super.writeBytes(msg + "\n");
  313. return;
  314. }
  315.  
  316. if (mac != null)
  317. {
  318. byte[] hash = mac.doFinal(msg.getBytes());
  319. msg = new String(Base64.encode(hash)) + " " + msg;
  320. assert msg.matches("[" + B64 + "]{43}= [\\s[^\\s]]+");
  321. }
  322.  
  323. if (cipher != null)
  324. {
  325. super.writeBytes(new String(encode(msg.getBytes())) + "\n");
  326. return;
  327. }
  328.  
  329. super.writeBytes(new String(Base64.encode(msg.getBytes())) + "\n");
  330. return;
  331. }
  332. }
  333.  
  334. /*==========================================================================*/
  335.  
  336. static class HashError
  337. extends java.lang.RuntimeException
  338. {
  339. public HashError()
  340. {
  341. super();
  342. }
  343. }
  344. }
  345.