2c9e0c772c98886f2201929f68404d87d12f165d
[iotcloud.git] / src / java / iotcloud / CloudComm.java
1 package iotcloud;
2 import java.io.*;
3 import java.net.*;
4 import java.util.Arrays;
5 import javax.crypto.*;
6 import javax.crypto.spec.*;
7 import java.security.SecureRandom;
8
9 class CloudComm {
10         String baseurl;
11         Cipher encryptcipher;
12         Cipher decryptcipher;
13         Mac mac;
14         byte[] salt;
15         SecretKeySpec key;
16         static final int SALT_SIZE = 8;
17
18         
19         CloudComm() {
20         }
21
22         CloudComm(String _baseurl, String password) {
23                 this.baseurl=_baseurl;
24                 initCloud(password);
25         }
26
27         private void initKey(String password) {
28                 try {
29                         salt=new byte[SALT_SIZE];
30                         PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
31                         SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec);
32                         this.key = new SecretKeySpec(tmpkey.getEncoded(), "AES");
33                 } catch (Exception e) {
34                         e.printStackTrace();
35                         throw new Error("Failed generating key.");
36                 }
37         }
38
39         private void initCloud(String password) {
40                 try {
41                         initKey(password);
42                         mac = Mac.getInstance("HmacSHA256");
43                         mac.init(key);
44                 } catch (Exception e) {
45                         e.printStackTrace();
46                         throw new Error("Failed To Initialize Ciphers");
47                 }
48         }
49         
50         private URL buildRequest(boolean isput, long sequencenumber, long maxentries) throws IOException {
51                 String reqstring=isput?"req=putslot":"req=getslot";
52                 String urlstr=baseurl+"?"+reqstring+"&seq="+sequencenumber;
53                 if (maxentries != 0)
54                         urlstr += "&max="+maxentries;
55                 return new URL(urlstr);
56         }
57
58         public Slot[] putSlot(Slot slot, int max) {
59                 try {
60                         long sequencenumber=slot.getSequenceNumber();
61                         byte[] bytes=slot.encode(mac);
62
63                         URL url=buildRequest(true, sequencenumber, max);
64                         URLConnection con=url.openConnection();
65                         HttpURLConnection http = (HttpURLConnection) con;
66                         http.setRequestMethod("POST");
67                         http.setFixedLengthStreamingMode(bytes.length);
68                         http.setDoOutput(true);
69                         http.connect();
70                         OutputStream os=http.getOutputStream();
71                         os.write(bytes);
72                         System.out.println(http.getResponseMessage());
73
74                         InputStream is=http.getInputStream();
75                         DataInputStream dis=new DataInputStream(is);
76                         byte[] resptype=new byte[7];
77                         dis.readFully(resptype);
78                         if (Arrays.equals(resptype, "getslot".getBytes()))
79                                 return processSlots(dis);
80                         else if (Arrays.equals(resptype, "putslot".getBytes()))
81                                 return null;
82                         else
83                                 throw new Error("Bad response to putslot");
84                 } catch (Exception e) {
85                         throw new Error("putSlot failed");
86                 }
87         }
88
89         /*
90                         Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
91                         encryptCipher.init(Cipher.ENCRYPT_MODE, secret);
92                         Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
93                         decryptCipher.init(Cipher.DECRYPT_MODE, secret);
94         */
95         
96         public Slot[] getSlots(long sequencenumber) {
97                 try {
98                         URL url=buildRequest(false, sequencenumber, 0);
99                         URLConnection con=url.openConnection();
100                         HttpURLConnection http = (HttpURLConnection) con;
101                         http.setRequestMethod("POST");
102                         http.connect();
103                         System.out.println(http.getResponseMessage());
104                         InputStream is=http.getInputStream();
105
106                         DataInputStream dis=new DataInputStream(is);
107                         byte[] resptype=new byte[7];
108                         dis.readFully(resptype);
109                         if (!Arrays.equals(resptype, "getslot".getBytes()))
110                                 throw new Error("Bad Response: "+new String(resptype));
111                         else
112                                 return processSlots(dis);
113                 } catch (Exception e) {
114                         throw new Error("getSlots failed");
115                 }
116         }
117
118         Slot[] processSlots(DataInputStream dis) throws IOException {
119                 int numberofslots=dis.readInt();
120                 int[] sizesofslots=new int[numberofslots];
121                 Slot[] slots=new Slot[numberofslots];
122                 for(int i=0; i<numberofslots; i++)
123                         sizesofslots[i]=dis.readInt();
124
125                 for(int i=0; i<numberofslots; i++) {
126                         byte[] data=new byte[sizesofslots[i]];
127                         dis.readFully(data);
128                         slots[i]=Slot.decode(data, mac);
129                 }
130                 dis.close();
131                 return slots;
132         }
133 }