--- a/app/src/main/java/com/isode/stroke/sasl/SCRAMSHA1ClientAuthenticator.java Sun Mar 15 21:08:23 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2010, Isode Limited, London, England.
- * All rights reserved.
- */
-/*
- * Copyright (c) 2010, Remko Tronçon.
- * All rights reserved.
- */
-package com.isode.stroke.sasl;
-
-import com.isode.stroke.base.ByteArray;
-import com.isode.stroke.stringcodecs.Base64;
-import com.isode.stroke.stringcodecs.HMACSHA1;
-import com.isode.stroke.stringcodecs.PBKDF2;
-import com.isode.stroke.stringcodecs.SHA1;
-import java.text.Normalizer;
-import java.text.Normalizer.Form;
-import java.util.HashMap;
-import java.util.Map;
-
-public class SCRAMSHA1ClientAuthenticator extends ClientAuthenticator {
-
- static String escape(String s) {
- String result = "";
- for (int i = 0; i < s.length(); ++i) {
- if (s.charAt(i) == ',') {
- result += "=2C";
- } else if (s.charAt(i) == '=') {
- result += "=3D";
- } else {
- result += s.charAt(i);
- }
- }
- return result;
- }
-
- public SCRAMSHA1ClientAuthenticator(String nonce) {
- this(nonce, false);
- }
- public SCRAMSHA1ClientAuthenticator(String nonce, boolean useChannelBinding) {
- super(useChannelBinding ? "SCRAM-SHA-1-PLUS" : "SCRAM-SHA-1");
- step = Step.Initial;
- clientnonce = nonce;
- this.useChannelBinding = useChannelBinding;
- }
-
- public void setTLSChannelBindingData(ByteArray channelBindingData) {
- tlsChannelBindingData = channelBindingData;
- }
-
- public ByteArray getResponse() {
- if (step.equals(Step.Initial)) {
- return ByteArray.plus(getGS2Header(), getInitialBareClientMessage());
- } else if (step.equals(Step.Proof)) {
- ByteArray clientKey = HMACSHA1.getResult(saltedPassword, new ByteArray("Client Key"));
- ByteArray storedKey = SHA1.getHash(clientKey);
- ByteArray clientSignature = HMACSHA1.getResult(storedKey, authMessage);
- ByteArray clientProof = clientKey;
- byte[] clientProofData = clientProof.getData();
- for (int i = 0; i < clientProofData.length; ++i) {
- clientProofData[i] ^= clientSignature.getData()[i];
- }
- ByteArray result = getFinalMessageWithoutProof().append(",p=").append(Base64.encode(clientProof));
- return result;
- } else {
- return null;
- }
- }
-
- public boolean setChallenge(ByteArray challenge) {
- if (step.equals(Step.Initial)) {
- if (challenge == null) {
- return false;
- }
- initialServerMessage = challenge;
-
- Map<Character, String> keys = parseMap(initialServerMessage.toString());
-
- // Extract the salt
- ByteArray salt = Base64.decode(keys.get('s'));
-
- // Extract the server nonce
- String clientServerNonce = keys.get('r');
- if (clientServerNonce.length() <= clientnonce.length()) {
- return false;
- }
- String receivedClientNonce = clientServerNonce.substring(0, clientnonce.length());
- if (!receivedClientNonce.equals(clientnonce)) {
- return false;
- }
- serverNonce = new ByteArray(clientServerNonce.substring(clientnonce.length()));
-
-
- // Extract the number of iterations
- int iterations = 0;
- try {
- iterations = Integer.parseInt(keys.get('i'));
- } catch (NumberFormatException e) {
- return false;
- }
- if (iterations <= 0) {
- return false;
- }
-
- ByteArray channelBindData = new ByteArray();
- if (useChannelBinding && tlsChannelBindingData != null) {
- channelBindData = tlsChannelBindingData;
- }
-
- // Compute all the values needed for the server signature
- saltedPassword = PBKDF2.encode(new ByteArray(SASLPrep(getPassword())), salt, iterations);
- authMessage = getInitialBareClientMessage().append(",").append(initialServerMessage).append(",").append(getFinalMessageWithoutProof());
- ByteArray serverKey = HMACSHA1.getResult(saltedPassword, new ByteArray("Server Key"));
- serverSignature = HMACSHA1.getResult(serverKey, authMessage);
-
- step = Step.Proof;
- return true;
- } else if (step.equals(step.Proof)) {
- ByteArray result = new ByteArray("v=").append(new ByteArray(Base64.encode(serverSignature)));
- step = Step.Final;
- return challenge != null && challenge.equals(result);
- } else {
- return true;
- }
- }
-
- private String SASLPrep(String source) {
- return Normalizer.normalize(source, Form.NFKC); /* FIXME: Implement real SASLPrep */
- }
-
- private Map<Character, String> parseMap(String s) {
- HashMap<Character, String> result = new HashMap<Character, String>();
- if (s.length() > 0) {
- char key = '~'; /* initialise so it'll compile */
- String value = "";
- int i = 0;
- boolean expectKey = true;
- while (i < s.length()) {
- if (expectKey) {
- key = s.charAt(i);
- expectKey = false;
- i++;
- } else if (s.charAt(i) == ',') {
- result.put(key, value);
- value = "";
- expectKey = true;
- } else {
- value += s.charAt(i);
- }
- i++;
- }
- result.put(key, value);
- }
- return result;
- }
-
- private ByteArray getInitialBareClientMessage() {
- String authenticationID = SASLPrep(getAuthenticationID());
- return new ByteArray("n=" + escape(authenticationID) + ",r=" + clientnonce);
- }
-
- private ByteArray getGS2Header() {
-
- ByteArray channelBindingHeader = new ByteArray("n");
- if (tlsChannelBindingData != null) {
- if (useChannelBinding) {
- channelBindingHeader = new ByteArray("p=tls-unique");
- }
- else {
- channelBindingHeader = new ByteArray("y");
- }
- }
- return new ByteArray().append(channelBindingHeader).append(",").append(getAuthorizationID().isEmpty() ? new ByteArray() : new ByteArray("a=" + escape(getAuthorizationID()))).append(",");
- }
-
- private ByteArray getFinalMessageWithoutProof() {
- ByteArray channelBindData = new ByteArray();
- if (useChannelBinding && tlsChannelBindingData != null) {
- channelBindData = tlsChannelBindingData;
- }
- return new ByteArray("c=" + Base64.encode(new ByteArray(getGS2Header()).append(channelBindData)) + ",r=" + clientnonce).append(serverNonce);
- }
-
- private enum Step {
-
- Initial,
- Proof,
- Final
- };
- private Step step;
- private String clientnonce = "";
- private ByteArray initialServerMessage = new ByteArray();
- private ByteArray serverNonce = new ByteArray();
- private ByteArray authMessage = new ByteArray();
- private ByteArray saltedPassword = new ByteArray();
- private ByteArray serverSignature = new ByteArray();
- private boolean useChannelBinding;
- private ByteArray tlsChannelBindingData;
-}