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