17c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/*
27c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Copyright (C) 2009 Google Inc.  All rights reserved.
37c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
47c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Licensed under the Apache License, Version 2.0 (the "License");
57c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * you may not use this file except in compliance with the License.
67c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * You may obtain a copy of the License at
77c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
87c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *      http://www.apache.org/licenses/LICENSE-2.0
97c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Unless required by applicable law or agreed to in writing, software
117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * distributed under the License is distributed on an "AS IS" BASIS,
127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * See the License for the specific language governing permissions and
147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * limitations under the License.
157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpackage com.google.polo.pairing;
187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.exception.PoloException;
207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.security.MessageDigest;
227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.security.NoSuchAlgorithmException;
237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.security.PublicKey;
247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.security.cert.Certificate;
257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.security.interfaces.RSAPublicKey;
267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.util.Arrays;
277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/**
297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Class to represent the out-of-band secret transmitted during pairing.
307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpublic class PoloChallengeResponse {
327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Hash algorithm to generate secret.
357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  private static final String HASH_ALGORITHM = "SHA-256";
377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Optional handler for debug log messages.
407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  private DebugLogger mLogger;
427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Certificate of the local peer in the protocol.
457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  private Certificate mClientCertificate;
477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Certificate of the remote peer in the protocol.
507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  private Certificate mServerCertificate;
527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Creates a new callenge-response generator object.
557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @param clientCert  the certificate of the client node
577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @param serverCert  the certificate of the server node
587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @param logger      a listener for debugging messages; may be null
597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public PoloChallengeResponse(Certificate clientCert, Certificate serverCert,
617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      DebugLogger logger) {
627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    mClientCertificate = clientCert;
637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    mServerCertificate = serverCert;
647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    mLogger = logger;
657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Returns the alpha value to be used in pairing.
697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <p>
707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * From the Polo design document, `alpha` is the value h(K_a | K_b | R_a):
717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * for an RSA public key, that is:
727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <ul>
737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <li>the client key's modulus,</li>
747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <li>the client key's public exponent,</li>
757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <li>the server key's modulus,</li>
767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <li>the server key's public exponent,</li>
777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <li>the random nonce.</li>
787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @param   nonce          the nonce to use for computation
807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @return                 the alpha value, as a byte array
817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @throws  PoloException  if the secret could not be computed
827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public byte[] getAlpha(byte[] nonce) throws PoloException {
847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    PublicKey clientPubKey = mClientCertificate.getPublicKey();
857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    PublicKey serverPubKey = mServerCertificate.getPublicKey();
867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logDebug("getAlpha, nonce=" + PoloUtil.bytesToHexString(nonce));
887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    if (!(clientPubKey instanceof RSAPublicKey) ||
907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        !(serverPubKey instanceof RSAPublicKey)) {
917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throw new PoloException("Polo only supports RSA public keys");
927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    RSAPublicKey clientPubRsa = (RSAPublicKey) clientPubKey;
957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    RSAPublicKey serverPubRsa = (RSAPublicKey) serverPubKey;
967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    MessageDigest digest;
987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    try {
997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      digest = MessageDigest.getInstance(HASH_ALGORITHM);
1007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    } catch (NoSuchAlgorithmException e) {
1017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throw new PoloException("Could not get digest algorithm", e);
1027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] digestBytes;
1057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] clientModulus = clientPubRsa.getModulus().abs().toByteArray();
1067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] clientExponent =
1077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        clientPubRsa.getPublicExponent().abs().toByteArray();
1087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] serverModulus = serverPubRsa.getModulus().abs().toByteArray();
1097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] serverExponent =
1107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        serverPubRsa.getPublicExponent().abs().toByteArray();
1117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    // Per "Polo Implementation Overview", section 6.1, leading null bytes must
1137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    // be removed prior to hashing the key material.
1147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    clientModulus = removeLeadingNullBytes(clientModulus);
1157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    clientExponent = removeLeadingNullBytes(clientExponent);
1167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    serverModulus = removeLeadingNullBytes(serverModulus);
1177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    serverExponent = removeLeadingNullBytes(serverExponent);
1187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logVerbose("Hash inputs, in order: ");
1207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logVerbose("   client modulus: " + PoloUtil.bytesToHexString(clientModulus));
1217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logVerbose("  client exponent: " + PoloUtil.bytesToHexString(clientExponent));
1227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logVerbose("   server modulus: " + PoloUtil.bytesToHexString(serverModulus));
1237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logVerbose("  server exponent: " + PoloUtil.bytesToHexString(serverExponent));
1247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logVerbose("            nonce: " + PoloUtil.bytesToHexString(nonce));
1257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    // Per "Polo Implementation Overview", section 6.1, client key material is
1277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    // hashed first, followed by the server key material, followed by the
1287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    // nonce.
1297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    digest.update(clientModulus);
1307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    digest.update(clientExponent);
1317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    digest.update(serverModulus);
1327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    digest.update(serverExponent);
1337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    digest.update(nonce);
1347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    digestBytes = digest.digest();
1367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logDebug("Generated hash: " + PoloUtil.bytesToHexString(digestBytes));
1377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return digestBytes;
1387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
1397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
1417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Returns the gamma value to be used in pairing, i.e. the concatenation
1427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * of the alpha value with the nonce.
1437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <p>
1447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * The returned value with be twice the byte length of the nonce.
1457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
1467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @throws PoloException  if the secret could not be computed
1477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
1487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public byte[] getGamma(byte[] nonce) throws PoloException {
1497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      byte[] alphaBytes = getAlpha(nonce);
1507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      assert(alphaBytes.length >= nonce.length);
1517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      byte[] result = new byte[nonce.length * 2];
1537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      System.arraycopy(alphaBytes, 0, result, 0, nonce.length);
1557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      System.arraycopy(nonce, 0, result, nonce.length, nonce.length);
1567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      return result;
1587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
1597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
1617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Extracts and returns the nonce portion of a given gamma value.
1627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
1637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public byte[] extractNonce(byte[] gamma) {
1647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    if ((gamma.length < 2) || (gamma.length % 2 != 0)) {
1657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throw new IllegalArgumentException();
1667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    int nonceLength = gamma.length / 2;
1687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] nonce = new byte[nonceLength];
1697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    System.arraycopy(gamma, nonceLength, nonce, 0, nonceLength);
1707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return nonce;
1717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
1727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
1747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Returns {@code true} if the gamma value matches the locally computed value.
1757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <p>
1767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * The computed value is determined by extracting the nonce portion of the
1777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * gamma value.
1787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
1797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @throws PoloException  if the value could not be computed
1807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
1817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public boolean checkGamma(byte[] gamma) throws PoloException {
1827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] nonce;
1847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    try {
1857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      nonce = extractNonce(gamma);
1867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    } catch (IllegalArgumentException e) {
1877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      logDebug("Illegal nonce value.");
1887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      return false;
1897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logDebug("Nonce is: " + PoloUtil.bytesToHexString(nonce));
1917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logDebug("User gamma is: " + PoloUtil.bytesToHexString(gamma));
1927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    logDebug("Generated gamma is: " + PoloUtil.bytesToHexString(getGamma(nonce)));
1937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return Arrays.equals(gamma, getGamma(nonce));
1947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
1957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
1977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Strips leading null bytes from a byte array, returning a new copy.
1987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <p>
1997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * As a special case, if the input array consists entirely of null bytes,
2007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * then an array with a single null element will be returned.
2017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
2027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  private byte[] removeLeadingNullBytes(byte[] inArray) {
2037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    int offset = 0;
2047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    while (offset < inArray.length & inArray[offset] == 0) {
2057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      offset += 1;
2067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] result = new byte[inArray.length - offset];
2087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    for (int i=offset; i < inArray.length; i++) {
2097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      result[i - offset] = inArray[i];
2107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return result;
2127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
2137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  private void logDebug(String message) {
2157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    if (mLogger != null) {
2167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      mLogger.debug(message);
2177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
2197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  private void logVerbose(String message) {
2217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    if (mLogger != null) {
2227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      mLogger.verbose(message);
2237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
2257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public static interface DebugLogger {
2277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
2287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Logs debugging information from challenge-response generation.
2297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
2307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public void debug(String message);
2317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
2337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Logs verbose debugging information from challenge-response generation.
2347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
2357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public void verbose(String message);
2367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
2387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
240