|
1 /* |
|
2 * otr4j, the open source java otr library. |
|
3 * |
|
4 * Distributable under LGPL license. |
|
5 * See terms of license at gnu.org. |
|
6 */ |
|
7 package net.java.otr4j.session; |
|
8 |
|
9 import java.math.BigInteger; |
|
10 import java.nio.ByteBuffer; |
|
11 import java.security.KeyPair; |
|
12 import java.util.Arrays; |
|
13 import java.util.logging.Logger; |
|
14 |
|
15 import javax.crypto.interfaces.DHPublicKey; |
|
16 |
|
17 import net.java.otr4j.OtrException; |
|
18 import net.java.otr4j.crypto.OtrCryptoEngine; |
|
19 import net.java.otr4j.crypto.OtrCryptoEngineImpl; |
|
20 import net.java.otr4j.io.SerializationUtils; |
|
21 |
|
22 /** |
|
23 * |
|
24 * @author George Politis |
|
25 */ |
|
26 class SessionKeysImpl implements SessionKeys { |
|
27 |
|
28 private static Logger logger = Logger.getLogger(SessionKeysImpl.class |
|
29 .getName()); |
|
30 private String keyDescription; |
|
31 |
|
32 public SessionKeysImpl(int localKeyIndex, int remoteKeyIndex) { |
|
33 if (localKeyIndex == 0) |
|
34 keyDescription = "(Previous local, "; |
|
35 else |
|
36 keyDescription = "(Most recent local, "; |
|
37 |
|
38 if (remoteKeyIndex == 0) |
|
39 keyDescription += "Previous remote)"; |
|
40 else |
|
41 keyDescription += "Most recent remote)"; |
|
42 |
|
43 } |
|
44 |
|
45 public void setLocalPair(KeyPair keyPair, int localPairKeyID) { |
|
46 this.localPair = keyPair; |
|
47 this.setLocalKeyID(localPairKeyID); |
|
48 logger.finest(keyDescription + " current local key ID: " |
|
49 + this.getLocalKeyID()); |
|
50 this.reset(); |
|
51 } |
|
52 |
|
53 public void setRemoteDHPublicKey(DHPublicKey pubKey, int remoteKeyID) { |
|
54 this.setRemoteKey(pubKey); |
|
55 this.setRemoteKeyID(remoteKeyID); |
|
56 logger.finest(keyDescription + " current remote key ID: " |
|
57 + this.getRemoteKeyID()); |
|
58 this.reset(); |
|
59 } |
|
60 |
|
61 private byte[] sendingCtr = new byte[16]; |
|
62 private byte[] receivingCtr = new byte[16]; |
|
63 |
|
64 public void incrementSendingCtr() { |
|
65 logger.finest("Incrementing counter for (localkeyID, remoteKeyID) = (" |
|
66 + getLocalKeyID() + "," + getRemoteKeyID() + ")"); |
|
67 // logger.debug("Counter prior increament: " + |
|
68 // Utils.dump(sendingCtr, |
|
69 // true, 16)); |
|
70 for (int i = 7; i >= 0; i--) |
|
71 if (++sendingCtr[i] != 0) |
|
72 break; |
|
73 // logger.debug("Counter after increament: " + |
|
74 // Utils.dump(sendingCtr, |
|
75 // true, 16)); |
|
76 } |
|
77 |
|
78 public byte[] getSendingCtr() { |
|
79 return sendingCtr; |
|
80 } |
|
81 |
|
82 public byte[] getReceivingCtr() { |
|
83 return receivingCtr; |
|
84 } |
|
85 |
|
86 public void setReceivingCtr(byte[] ctr) { |
|
87 for (int i = 0; i < ctr.length; i++) |
|
88 receivingCtr[i] = ctr[i]; |
|
89 } |
|
90 |
|
91 private void reset() { |
|
92 logger.finest("Resetting " + keyDescription + " session keys."); |
|
93 Arrays.fill(this.sendingCtr, (byte) 0x00); |
|
94 Arrays.fill(this.receivingCtr, (byte) 0x00); |
|
95 this.sendingAESKey = null; |
|
96 this.receivingAESKey = null; |
|
97 this.sendingMACKey = null; |
|
98 this.receivingMACKey = null; |
|
99 this.setIsUsedReceivingMACKey(false); |
|
100 this.s = null; |
|
101 if (getLocalPair() != null && getRemoteKey() != null) { |
|
102 this.isHigh = ((DHPublicKey) getLocalPair().getPublic()).getY() |
|
103 .abs().compareTo(getRemoteKey().getY().abs()) == 1; |
|
104 } |
|
105 |
|
106 } |
|
107 |
|
108 private byte[] h1(byte b) throws OtrException { |
|
109 |
|
110 try { |
|
111 byte[] secbytes = SerializationUtils.writeMpi(getS()); |
|
112 |
|
113 int len = secbytes.length + 1; |
|
114 ByteBuffer buff = ByteBuffer.allocate(len); |
|
115 buff.put(b); |
|
116 buff.put(secbytes); |
|
117 byte[] result = new OtrCryptoEngineImpl().sha1Hash(buff.array()); |
|
118 return result; |
|
119 } catch (Exception e) { |
|
120 throw new OtrException(e); |
|
121 } |
|
122 } |
|
123 |
|
124 public byte[] getSendingAESKey() throws OtrException { |
|
125 if (sendingAESKey != null) |
|
126 return sendingAESKey; |
|
127 |
|
128 byte sendbyte = LOW_SEND_BYTE; |
|
129 if (this.isHigh) |
|
130 sendbyte = HIGH_SEND_BYTE; |
|
131 |
|
132 byte[] h1 = h1(sendbyte); |
|
133 |
|
134 byte[] key = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH]; |
|
135 ByteBuffer buff = ByteBuffer.wrap(h1); |
|
136 buff.get(key); |
|
137 logger.finest("Calculated sending AES key."); |
|
138 this.sendingAESKey = key; |
|
139 return sendingAESKey; |
|
140 } |
|
141 |
|
142 public byte[] getReceivingAESKey() throws OtrException { |
|
143 if (receivingAESKey != null) |
|
144 return receivingAESKey; |
|
145 |
|
146 byte receivebyte = LOW_RECEIVE_BYTE; |
|
147 if (this.isHigh) |
|
148 receivebyte = HIGH_RECEIVE_BYTE; |
|
149 |
|
150 byte[] h1 = h1(receivebyte); |
|
151 |
|
152 byte[] key = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH]; |
|
153 ByteBuffer buff = ByteBuffer.wrap(h1); |
|
154 buff.get(key); |
|
155 logger.finest("Calculated receiving AES key."); |
|
156 this.receivingAESKey = key; |
|
157 |
|
158 return receivingAESKey; |
|
159 } |
|
160 |
|
161 public byte[] getSendingMACKey() throws OtrException { |
|
162 if (sendingMACKey != null) |
|
163 return sendingMACKey; |
|
164 |
|
165 sendingMACKey = new OtrCryptoEngineImpl().sha1Hash(getSendingAESKey()); |
|
166 logger.finest("Calculated sending MAC key."); |
|
167 return sendingMACKey; |
|
168 } |
|
169 |
|
170 public byte[] getReceivingMACKey() throws OtrException { |
|
171 if (receivingMACKey == null) { |
|
172 receivingMACKey = new OtrCryptoEngineImpl() |
|
173 .sha1Hash(getReceivingAESKey()); |
|
174 logger.finest("Calculated receiving AES key."); |
|
175 } |
|
176 return receivingMACKey; |
|
177 } |
|
178 |
|
179 private BigInteger getS() throws OtrException { |
|
180 if (s == null) { |
|
181 s = new OtrCryptoEngineImpl().generateSecret(getLocalPair() |
|
182 .getPrivate(), getRemoteKey()); |
|
183 logger.finest("Calculating shared secret S."); |
|
184 } |
|
185 return s; |
|
186 } |
|
187 |
|
188 public void setS(BigInteger s) { |
|
189 this.s = s; |
|
190 } |
|
191 |
|
192 public void setIsUsedReceivingMACKey(Boolean isUsedReceivingMACKey) { |
|
193 this.isUsedReceivingMACKey = isUsedReceivingMACKey; |
|
194 } |
|
195 |
|
196 public Boolean getIsUsedReceivingMACKey() { |
|
197 return isUsedReceivingMACKey; |
|
198 } |
|
199 |
|
200 private void setLocalKeyID(int localKeyID) { |
|
201 this.localKeyID = localKeyID; |
|
202 } |
|
203 |
|
204 public int getLocalKeyID() { |
|
205 return localKeyID; |
|
206 } |
|
207 |
|
208 private void setRemoteKeyID(int remoteKeyID) { |
|
209 this.remoteKeyID = remoteKeyID; |
|
210 } |
|
211 |
|
212 public int getRemoteKeyID() { |
|
213 return remoteKeyID; |
|
214 } |
|
215 |
|
216 private void setRemoteKey(DHPublicKey remoteKey) { |
|
217 this.remoteKey = remoteKey; |
|
218 } |
|
219 |
|
220 public DHPublicKey getRemoteKey() { |
|
221 return remoteKey; |
|
222 } |
|
223 |
|
224 public KeyPair getLocalPair() { |
|
225 return localPair; |
|
226 } |
|
227 |
|
228 private int localKeyID; |
|
229 private int remoteKeyID; |
|
230 private DHPublicKey remoteKey; |
|
231 private KeyPair localPair; |
|
232 |
|
233 private byte[] sendingAESKey; |
|
234 private byte[] receivingAESKey; |
|
235 private byte[] sendingMACKey; |
|
236 private byte[] receivingMACKey; |
|
237 private Boolean isUsedReceivingMACKey; |
|
238 private BigInteger s; |
|
239 private Boolean isHigh; |
|
240 } |