· 7 years ago · May 18, 2018, 03:44 PM
1package example.ws.handler;
2
3import static javax.xml.bind.DatatypeConverter.printHexBinary;
4
5import java.security.Key;
6import java.security.MessageDigest;
7import java.security.NoSuchAlgorithmException;
8import java.util.Arrays;
9import java.util.Set;
10
11import javax.crypto.KeyGenerator;
12import javax.crypto.Mac;
13import javax.crypto.SecretKey;
14import javax.xml.namespace.QName;
15import javax.xml.soap.Name;
16import javax.xml.soap.SOAPEnvelope;
17import javax.xml.soap.SOAPException;
18import javax.xml.soap.SOAPHeader;
19import javax.xml.soap.SOAPHeaderElement;
20import javax.xml.soap.SOAPMessage;
21import javax.xml.soap.SOAPPart;
22import javax.xml.ws.handler.MessageContext;
23import javax.xml.ws.handler.soap.SOAPHandler;
24import javax.xml.ws.handler.soap.SOAPMessageContext;
25
26import org.w3c.dom.NodeList;
27
28import pt.ulisboa.tecnico.sdis.kerby.SecurityHelper;
29
30
31public class MacHandler implements SOAPHandler<SOAPMessageContext> {
32
33 /** Digest algorithm. */
34 private static final String DIGEST_ALGO = "SHA-256";
35
36 /** Symmetric algorithm key size. */
37 private static final int SYM_KEY_SIZE = 128;
38
39 /** Symmetric cryptography algorithm. */
40 private static final String SYM_ALGO = "AES";
41
42 /** Message authentication code algorithm. */
43 private static final String MAC_ALGO = "HmacSHA256";
44
45 protected static String Server_Name_pass = "etxgJMK";
46
47 @Override
48 public void close(MessageContext messageContext) {
49 //nothing to do
50 }
51
52 @Override
53 public boolean handleFault(SOAPMessageContext smc) {
54 System.out.println("Ignoring fault message...");
55 throw new RuntimeException();
56
57 }
58
59 public boolean handleMessage(SOAPMessageContext smc) {
60
61 Boolean outbound = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
62 if (outbound) {
63 try {
64 // get SOAP envelope header
65 SOAPMessage msg = smc.getMessage();
66 SOAPPart sp = msg.getSOAPPart();
67 SOAPEnvelope se = sp.getEnvelope();
68 SOAPHeader sh = se.getHeader();
69
70 // check header
71 if (sh == null) {
72 sh = se.addHeader();
73 }
74
75 //Get the Text Content from SOAPBody
76 String content = se.getBody().getTextContent();
77
78 //Convert to Bytes
79 final byte[] plainBytes = content.getBytes();
80
81 MessageDigest messageDigest = MessageDigest.getInstance(DIGEST_ALGO);
82
83 //Generate Digest
84 messageDigest.update(plainBytes);
85 byte[] digest = messageDigest.digest();
86
87
88 // generate MAC from server_name_pass
89
90 final Key keyForMac = SecurityHelper.generateKeyFromPassword(Server_Name_pass);
91 byte[] cipherDigest = makeMAC(digest, keyForMac);
92 String stringCipherDigest = printHexBinary(cipherDigest);
93
94 // add header element (name, namespace prefix, namespace)
95 Name name = se.createName("myMac", "Mac", "http://mac");
96 SOAPHeaderElement mac_element = sh.addHeaderElement(name);
97
98 // add header element value
99 mac_element.addTextNode(stringCipherDigest);
100
101 } catch (SOAPException e) {
102 System.out.print("Caught exception in MacHandler: ");
103 System.out.println(e);
104 System.out.println("Continue normal processing...");
105 } catch (NoSuchAlgorithmException e) {
106 System.out.print("Caught exception in MacHandler: ");
107 System.out.println(e);
108 System.out.println("Continue normal processing...");
109 } catch (Exception e) {
110 System.out.print("Caught exception in MacHandler: ");
111 System.out.println(e);
112 System.out.println("Continue normal processing...");
113 }
114 }
115 if (!outbound) {
116 try {
117 // get SOAP envelope header
118 SOAPMessage msg = smc.getMessage();
119 SOAPPart sp = msg.getSOAPPart();
120 SOAPEnvelope se = sp.getEnvelope();
121 SOAPHeader sh = se.getHeader();
122
123 // check header
124 if (sh == null) {
125 sh = se.addHeader();
126 }
127
128 // get all elements with URI http://mac and myMac prefix, to get the mac Text content
129 NodeList nl = sh.getElementsByTagNameNS("http://mac", "myMac");
130 String macHeader = nl.item(0).getTextContent();
131
132 //convert to bytes
133 final byte[] plainBytes = macHeader.getBytes();
134
135 MessageDigest messageDigest = MessageDigest.getInstance(DIGEST_ALGO);
136
137 //Generate Digest
138 messageDigest.update(plainBytes);
139 byte[] digest = messageDigest.digest();
140 final Key keyForMac = SecurityHelper.generateKeyFromPassword(Server_Name_pass);
141 byte[] cipherDigest = makeMAC(digest, keyForMac);
142 //verify the MAC between request and reply
143 if (!verifyMAC(cipherDigest, plainBytes, keyForMac)) {
144 return false;
145 }
146
147 } catch (SOAPException e) {
148 System.out.print("Caught exception in MacHandler: ");
149 System.out.println(e);
150 System.out.println("Continue normal processing...");
151 } catch (Exception e) {
152 System.out.print("Caught exception in MacHandler: ");
153 System.out.println(e);
154 System.out.println("Continue normal processing...");
155 }
156 }
157 return true;
158 }
159
160 @Override
161 public Set<QName> getHeaders() {
162 return null;
163 }
164
165 /**DISCLAIMER: These functions are based on the crypto package that was given by the teachers **/
166
167 /** Generates a SecretKey for using in message authentication code. */
168 private static SecretKey generateMACKey(int keySize) throws Exception {
169 KeyGenerator keyGen = KeyGenerator.getInstance(SYM_ALGO);
170 keyGen.init(keySize);
171 SecretKey key = keyGen.generateKey();
172
173 return key;
174 }
175
176 /** Makes a message authentication code. */
177 private static byte[] makeMAC(byte[] bytes, Key key) throws Exception {
178 Mac cipher = Mac.getInstance(MAC_ALGO);
179 cipher.init(key);
180 byte[] cipherDigest = cipher.doFinal(bytes);
181 return cipherDigest;
182 }
183
184 /**
185 * Calculates new digest from text and compare it to the to deciphered
186 * digest.
187 */
188 private static boolean verifyMAC(byte[] cipherDigest, byte[] bytes, Key key) throws Exception {
189 Mac cipher = Mac.getInstance(MAC_ALGO);
190 cipher.init(key);
191 byte[] cipheredBytes = cipher.doFinal(bytes);
192 return Arrays.equals(cipherDigest, cipheredBytes);
193 }
194}