// Path: mobile/blackberry/src/org/bouncycastle/crypto/Mac.java
// public interface Mac
// {
//     /**
//      * Initialise the MAC.
//      *
//      * @param params the key and other data required by the MAC.
//      * @exception IllegalArgumentException if the params argument is
//      * inappropriate.
//      */
//     public void init(CipherParameters params)
//         throws IllegalArgumentException;
// 
//     /**
//      * Return the name of the algorithm the MAC implements.
//      *
//      * @return the name of the algorithm the MAC implements.
//      */
//     public String getAlgorithmName();
// 
//     /**
//      * Return the block size for this MAC (in bytes).
//      *
//      * @return the block size for this MAC in bytes.
//      */
//     public int getMacSize();
// 
//     /**
//      * add a single byte to the mac for processing.
//      *
//      * @param in the byte to be processed.
//      * @exception IllegalStateException if the MAC is not initialised.
//      */
//     public void update(byte in)
//         throws IllegalStateException;
// 
//     /**
//      * @param in the array containing the input.
//      * @param inOff the index in the array the data begins at.
//      * @param len the length of the input starting at inOff.
//      * @exception IllegalStateException if the MAC is not initialised.
//      * @exception DataLengthException if there isn't enough data in in.
//      */
//     public void update(byte[] in, int inOff, int len)
//         throws DataLengthException, IllegalStateException;
// 
//     /**
//      * Compute the final stage of the MAC writing the output to the out
//      * parameter.
//      * <p>
//      * doFinal leaves the MAC in the same state it was after the last init.
//      *
//      * @param out the array the MAC is to be output to.
//      * @param outOff the offset into the out buffer the output is to start at.
//      * @exception DataLengthException if there isn't enough space in out.
//      * @exception IllegalStateException if the MAC is not initialised.
//      */
//     public int doFinal(byte[] out, int outOff)
//         throws DataLengthException, IllegalStateException;
// 
//     /**
//      * Reset the MAC. At the end of resetting the MAC should be in the
//      * in the same state it was after the last init (if there was one).
//      */
//     public void reset();
// }


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import org.bouncycastle.crypto.Mac;
/*-
 * Copyright 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.authenticator.blackberry;



/**
 * An implementation of the HOTP generator specified by RFC 4226. Generates
 * short passcodes that may be used in challenge-response protocols or as
 * timeout passcodes that are only valid for a short period.
 *
 * The default passcode is a 6-digit decimal code and the default timeout
 * period is 5 minutes.
 */
public class PasscodeGenerator {
  /** Default decimal passcode length */
  private static final int PASS_CODE_LENGTH = 6;

  /** Default passcode timeout period (in seconds) */
  private static final int INTERVAL = 30;

  /** The number of previous and future intervals to check */
  private static final int ADJACENT_INTERVALS = 1;

  private static final int PIN_MODULO = pow(10, PASS_CODE_LENGTH);
  
  private static final int pow(int a, int b) {
    int result = 1;
    for (int i = 0; i < b; i++) {
      result *= a;
    }
    return result;
  }

  private final Signer signer;
  private final int codeLength;
  private final int intervalPeriod;

  /*
   * Using an interface to allow us to inject different signature
   * implementations.
   */
  interface Signer {
    byte[] sign(byte[] data);
  }

  /**
   * @param mac A {@link Mac} used to generate passcodes
   */
// Path: mobile/blackberry/src/org/bouncycastle/crypto/Mac.java
// public interface Mac
// {
//     /**
//      * Initialise the MAC.
//      *
//      * @param params the key and other data required by the MAC.
//      * @exception IllegalArgumentException if the params argument is
//      * inappropriate.
//      */
//     public void init(CipherParameters params)
//         throws IllegalArgumentException;
// 
//     /**
//      * Return the name of the algorithm the MAC implements.
//      *
//      * @return the name of the algorithm the MAC implements.
//      */
//     public String getAlgorithmName();
// 
//     /**
//      * Return the block size for this MAC (in bytes).
//      *
//      * @return the block size for this MAC in bytes.
//      */
//     public int getMacSize();
// 
//     /**
//      * add a single byte to the mac for processing.
//      *
//      * @param in the byte to be processed.
//      * @exception IllegalStateException if the MAC is not initialised.
//      */
//     public void update(byte in)
//         throws IllegalStateException;
// 
//     /**
//      * @param in the array containing the input.
//      * @param inOff the index in the array the data begins at.
//      * @param len the length of the input starting at inOff.
//      * @exception IllegalStateException if the MAC is not initialised.
//      * @exception DataLengthException if there isn't enough data in in.
//      */
//     public void update(byte[] in, int inOff, int len)
//         throws DataLengthException, IllegalStateException;
// 
//     /**
//      * Compute the final stage of the MAC writing the output to the out
//      * parameter.
//      * <p>
//      * doFinal leaves the MAC in the same state it was after the last init.
//      *
//      * @param out the array the MAC is to be output to.
//      * @param outOff the offset into the out buffer the output is to start at.
//      * @exception DataLengthException if there isn't enough space in out.
//      * @exception IllegalStateException if the MAC is not initialised.
//      */
//     public int doFinal(byte[] out, int outOff)
//         throws DataLengthException, IllegalStateException;
// 
//     /**
//      * Reset the MAC. At the end of resetting the MAC should be in the
//      * in the same state it was after the last init (if there was one).
//      */
//     public void reset();
// }


// Path: mobile/blackberry/src/com/google/authenticator/blackberry/PasscodeGenerator.java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import org.bouncycastle.crypto.Mac;

/*-
 * Copyright 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.authenticator.blackberry;



/**
 * An implementation of the HOTP generator specified by RFC 4226. Generates
 * short passcodes that may be used in challenge-response protocols or as
 * timeout passcodes that are only valid for a short period.
 *
 * The default passcode is a 6-digit decimal code and the default timeout
 * period is 5 minutes.
 */
public class PasscodeGenerator {
  /** Default decimal passcode length */
  private static final int PASS_CODE_LENGTH = 6;

  /** Default passcode timeout period (in seconds) */
  private static final int INTERVAL = 30;

  /** The number of previous and future intervals to check */
  private static final int ADJACENT_INTERVALS = 1;

  private static final int PIN_MODULO = pow(10, PASS_CODE_LENGTH);
  
  private static final int pow(int a, int b) {
    int result = 1;
    for (int i = 0; i < b; i++) {
      result *= a;
    }
    return result;
  }

  private final Signer signer;
  private final int codeLength;
  private final int intervalPeriod;

  /*
   * Using an interface to allow us to inject different signature
   * implementations.
   */
  interface Signer {
    byte[] sign(byte[] data);
  }

  /**
   * @param mac A {@link Mac} used to generate passcodes
   */
  public PasscodeGenerator(Mac mac) {