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