예제 #1
0
 // TODO
 public GMSSSigner(GMSSDigestProvider digest) {
   digestProvider = digest;
   messDigestTrees = digest.get();
   messDigestOTS = messDigestTrees;
   mdLength = messDigestTrees.getDigestSize();
   gmssRandom = new GMSSRandom(messDigestTrees);
 }
예제 #2
0
  /** Initializes the signature algorithm for signing a message. */
  private void initSign() {
    messDigestTrees.reset();
    // set private key and take from it ots key, auth, tree and key
    // counter, rootSign
    GMSSPrivateKeyParameters gmssPrivateKey = (GMSSPrivateKeyParameters) key;

    if (gmssPrivateKey.isUsed()) {
      throw new IllegalStateException("Private key already used");
    }

    // check if last signature has been generated
    if (gmssPrivateKey.getIndex(0) >= gmssPrivateKey.getNumLeafs(0)) {
      throw new IllegalStateException("No more signatures can be generated");
    }

    // get Parameterset
    this.gmssPS = gmssPrivateKey.getParameters();
    // get numLayer
    this.numLayer = gmssPS.getNumOfLayers();

    // get OTS Instance of lowest layer
    byte[] seed = gmssPrivateKey.getCurrentSeeds()[numLayer - 1];
    byte[] OTSSeed = new byte[mdLength];
    byte[] dummy = new byte[mdLength];
    System.arraycopy(seed, 0, dummy, 0, mdLength);
    OTSSeed =
        gmssRandom.nextSeed(
            dummy); // secureRandom.nextBytes(currentSeeds[currentSeeds.length-1]);secureRandom.nextBytes(OTSseed);
    this.ots =
        new WinternitzOTSignature(
            OTSSeed, digestProvider.get(), gmssPS.getWinternitzParameter()[numLayer - 1]);

    byte[][][] helpCurrentAuthPaths = gmssPrivateKey.getCurrentAuthPaths();
    currentAuthPaths = new byte[numLayer][][];

    // copy the main tree authentication path
    for (int j = 0; j < numLayer; j++) {
      currentAuthPaths[j] = new byte[helpCurrentAuthPaths[j].length][mdLength];
      for (int i = 0; i < helpCurrentAuthPaths[j].length; i++) {
        System.arraycopy(helpCurrentAuthPaths[j][i], 0, currentAuthPaths[j][i], 0, mdLength);
      }
    }

    // copy index
    index = new int[numLayer];
    System.arraycopy(gmssPrivateKey.getIndex(), 0, index, 0, numLayer);

    // copy subtreeRootSig
    byte[] helpSubtreeRootSig;
    subtreeRootSig = new byte[numLayer - 1][];
    for (int i = 0; i < numLayer - 1; i++) {
      helpSubtreeRootSig = gmssPrivateKey.getSubtreeRootSig(i);
      subtreeRootSig[i] = new byte[helpSubtreeRootSig.length];
      System.arraycopy(helpSubtreeRootSig, 0, subtreeRootSig[i], 0, helpSubtreeRootSig.length);
    }

    gmssPrivateKey.markUsed();
  }
예제 #3
0
 public GMSSRootCalc(int paramInt1, int paramInt2, GMSSDigestProvider paramGMSSDigestProvider) {
   this.bfm = paramInt1;
   this.bey = paramGMSSDigestProvider;
   this.bfu = paramGMSSDigestProvider.qH();
   this.bez = this.bfu.iJ();
   this.bfr = paramInt2;
   this.beQ = new int[paramInt1];
   int i = this.bez;
   this.bfq = ((byte[][]) Array.newInstance(Byte.TYPE, new int[] {paramInt1, i}));
   this.bfp = new byte[this.bez];
   this.bfo = new Vector[this.bfr - 1];
   paramInt1 = 0;
   while (paramInt1 < paramInt2 - 1) {
     this.bfo[paramInt1] = new Vector();
     paramInt1 += 1;
   }
 }
  /**
   * Updates the authentication path and root calculation for the tree after next (AUTH++, ROOT++)
   * in layer <code>layer</code>
   *
   * @param layer
   */
  private void updateNextNextAuthRoot(int layer) {

    byte[] OTSseed = new byte[mdLength];
    OTSseed = gmssRandom.nextSeed(nextNextSeeds[layer - 1]);

    // get the necessary leaf
    if (layer == numLayer - 1) { // lowest layer computes the necessary
      // leaf completely at this time
      WinternitzOTSignature ots =
          new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[layer]);
      this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], ots.getPublicKey());
    } else { // other layers use the precomputed leafs in nextNextLeaf
      this.nextNextRoot[layer - 1].update(
          nextNextSeeds[layer - 1], nextNextLeaf[layer - 1].getLeaf());
      this.nextNextLeaf[layer - 1].initLeafCalc(nextNextSeeds[layer - 1]);
    }
  }
예제 #5
0
  /**
   * This function verifies the signature of the message that has been updated, with the aid of the
   * public key.
   *
   * @param message the message
   * @param signature the signature associated with the message
   * @return true if the signature has been verified, false otherwise.
   */
  public boolean verifySignature(byte[] message, byte[] signature) {

    boolean success = false;
    // int halfSigLength = signature.length >>> 1;
    messDigestOTS.reset();
    WinternitzOTSVerify otsVerify;
    int otsSigLength;

    byte[] help = message;

    byte[] otsSig;
    byte[] otsPublicKey;
    byte[][] authPath;
    byte[] dest;
    int nextEntry = 0;
    int index;
    // Verify signature

    // --- begin with message = 'message that was signed'
    // and then in each step message = subtree root
    for (int j = numLayer - 1; j >= 0; j--) {
      otsVerify = new WinternitzOTSVerify(digestProvider.get(), gmssPS.getWinternitzParameter()[j]);
      otsSigLength = otsVerify.getSignatureLength();

      message = help;
      // get the subtree index
      index = gmssUtil.bytesToIntLittleEndian(signature, nextEntry);

      // 4 is the number of bytes in integer
      nextEntry += 4;

      // get one-time signature
      otsSig = new byte[otsSigLength];
      System.arraycopy(signature, nextEntry, otsSig, 0, otsSigLength);
      nextEntry += otsSigLength;

      // compute public OTS key from the one-time signature
      otsPublicKey = otsVerify.Verify(message, otsSig);

      // test if OTSsignature is correct
      if (otsPublicKey == null) {
        System.err.println("OTS Public Key is null in GMSSSignature.verify");
        return false;
      }

      // get authentication path from the signature
      authPath = new byte[gmssPS.getHeightOfTrees()[j]][mdLength];
      for (int i = 0; i < authPath.length; i++) {
        System.arraycopy(signature, nextEntry, authPath[i], 0, mdLength);
        nextEntry = nextEntry + mdLength;
      }

      // compute the root of the subtree from the authentication path
      help = new byte[mdLength];

      help = otsPublicKey;

      int count = 1 << authPath.length;
      count = count + index;

      for (int i = 0; i < authPath.length; i++) {
        dest = new byte[mdLength << 1];

        if ((count % 2) == 0) {
          System.arraycopy(help, 0, dest, 0, mdLength);
          System.arraycopy(authPath[i], 0, dest, mdLength, mdLength);
          count = count / 2;
        } else {
          System.arraycopy(authPath[i], 0, dest, 0, mdLength);
          System.arraycopy(help, 0, dest, mdLength, help.length);
          count = (count - 1) / 2;
        }
        messDigestTrees.update(dest, 0, dest.length);
        help = new byte[messDigestTrees.getDigestSize()];
        messDigestTrees.doFinal(help, 0);
      }
    }

    // now help contains the root of the maintree

    // test if help is equal to the GMSS public key
    if (Arrays.areEqual(pubKeyBytes, help)) {
      success = true;
    }

    return success;
  }
  /**
   * Computes the upcoming currentAuthpath of layer <code>layer</code> using the revisited
   * authentication path computation of Dahmen/Schneider 2008
   *
   * @param layer the actual layer
   */
  private void computeAuthPaths(int layer) {

    int Phi = index[layer];
    int H = heightOfTrees[layer];
    int K = this.K[layer];

    // update all nextSeeds for seed scheduling
    for (int i = 0; i < H - K; i++) {
      currentTreehash[layer][i].updateNextSeed(gmssRandom);
    }

    // STEP 1 of Algorithm
    int Tau = heightOfPhi(Phi);

    byte[] OTSseed = new byte[mdLength];
    OTSseed = gmssRandom.nextSeed(currentSeeds[layer]);

    // STEP 2 of Algorithm
    // if phi's parent on height tau + 1 if left node, store auth_tau
    // in keep_tau.
    // TODO check it, formerly was
    // int L = Phi / (int) Math.floor(Math.pow(2, Tau + 1));
    // L %= 2;
    int L = (Phi >>> (Tau + 1)) & 1;

    byte[] tempKeep = new byte[mdLength];
    // store the keep node not in keep[layer][tau/2] because it might be in
    // use
    // wait until the space is freed in step 4a
    if (Tau < H - 1 && L == 0) {
      System.arraycopy(currentAuthPaths[layer][Tau], 0, tempKeep, 0, mdLength);
    }

    byte[] help = new byte[mdLength];
    // STEP 3 of Algorithm
    // if phi is left child, compute and store leaf for next currentAuthPath
    // path,
    // (obtained by veriying current signature)
    if (Tau == 0) {
      // LEAFCALC !!!
      if (layer == numLayer - 1) { // lowest layer computes the
        // necessary leaf completely at this
        // time
        WinternitzOTSignature ots =
            new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[layer]);
        help = ots.getPublicKey();
      } else { // other layers use the precomputed leafs in
        // nextNextLeaf
        byte[] dummy = new byte[mdLength];
        System.arraycopy(currentSeeds[layer], 0, dummy, 0, mdLength);
        gmssRandom.nextSeed(dummy);
        help = upperLeaf[layer].getLeaf();
        this.upperLeaf[layer].initLeafCalc(dummy);

        // WinternitzOTSVerify otsver = new
        // WinternitzOTSVerify(algNames, otsIndex[layer]);
        // byte[] help2 = otsver.Verify(currentRoot[layer],
        // currentRootSig[layer]);
        // System.out.println(" --- " + layer + " " +
        // ByteUtils.toHexString(help) + " " +
        // ByteUtils.toHexString(help2));
      }
      System.arraycopy(help, 0, currentAuthPaths[layer][0], 0, mdLength);
    } else {
      // STEP 4a of Algorithm
      // get new left currentAuthPath node on height tau
      byte[] toBeHashed = new byte[mdLength << 1];
      System.arraycopy(currentAuthPaths[layer][Tau - 1], 0, toBeHashed, 0, mdLength);
      // free the shared keep[layer][tau/2]
      System.arraycopy(
          keep[layer][(int) Math.floor((Tau - 1) / 2)], 0, toBeHashed, mdLength, mdLength);
      messDigestTrees.update(toBeHashed, 0, toBeHashed.length);
      currentAuthPaths[layer][Tau] = new byte[messDigestTrees.getDigestSize()];
      messDigestTrees.doFinal(currentAuthPaths[layer][Tau], 0);

      // STEP 4b and 4c of Algorithm
      // copy right nodes to currentAuthPath on height 0..Tau-1
      for (int i = 0; i < Tau; i++) {

        // STEP 4b of Algorithm
        // 1st: copy from treehashs
        if (i < H - K) {
          if (currentTreehash[layer][i].wasFinished()) {
            System.arraycopy(
                currentTreehash[layer][i].getFirstNode(),
                0,
                currentAuthPaths[layer][i],
                0,
                mdLength);
            currentTreehash[layer][i].destroy();
          } else {
            System.err.println(
                "Treehash ("
                    + layer
                    + ","
                    + i
                    + ") not finished when needed in AuthPathComputation");
          }
        }

        // 2nd: copy precomputed values from Retain
        if (i < H - 1 && i >= H - K) {
          if (currentRetain[layer][i - (H - K)].size() > 0) {
            // pop element from retain
            System.arraycopy(
                currentRetain[layer][i - (H - K)].lastElement(),
                0,
                currentAuthPaths[layer][i],
                0,
                mdLength);
            currentRetain[layer][i - (H - K)].removeElementAt(
                currentRetain[layer][i - (H - K)].size() - 1);
          }
        }

        // STEP 4c of Algorithm
        // initialize new stack at heights 0..Tau-1
        if (i < H - K) {
          // create stacks anew
          int startPoint = Phi + 3 * (1 << i);
          if (startPoint < numLeafs[layer]) {
            // if (layer < 2) {
            // System.out.println("initialized TH " + i + " on layer
            // " + layer);
            // }
            currentTreehash[layer][i].initialize();
          }
        }
      }
    }

    // now keep space is free to use
    if (Tau < H - 1 && L == 0) {
      System.arraycopy(tempKeep, 0, keep[layer][(int) Math.floor(Tau / 2)], 0, mdLength);
    }

    // only update empty stack at height h if all other stacks have
    // tailnodes with height >h
    // finds active stack with lowest node height, choses lower index in
    // case of tie

    // on the lowest layer leafs must be computed at once, no precomputation
    // is possible. So all treehash updates are done at once here
    if (layer == numLayer - 1) {
      for (int tmp = 1; tmp <= (H - K) / 2; tmp++) {
        // index of the treehash instance that receives the next update
        int minTreehash = getMinTreehashIndex(layer);

        // if active treehash is found update with a leaf
        if (minTreehash >= 0) {
          try {
            byte[] seed = new byte[mdLength];
            System.arraycopy(
                this.currentTreehash[layer][minTreehash].getSeedActive(), 0, seed, 0, mdLength);
            byte[] seed2 = gmssRandom.nextSeed(seed);
            WinternitzOTSignature ots =
                new WinternitzOTSignature(seed2, this.digestProvider.get(), this.otsIndex[layer]);
            byte[] leaf = ots.getPublicKey();
            currentTreehash[layer][minTreehash].update(this.gmssRandom, leaf);
          } catch (Exception e) {
            System.out.println(e);
          }
        }
      }
    } else { // on higher layers the updates are done later
      this.minTreehash[layer] = getMinTreehashIndex(layer);
    }
  }
  /**
   * /**
   *
   * @param index tree indices
   * @param currentSeed seed for the generation of private OTS keys for the current subtrees (TREE)
   * @param nextNextSeed seed for the generation of private OTS keys for the subtrees after next
   *     (TREE++)
   * @param currentAuthPath array of current authentication paths (AUTHPATH)
   * @param nextAuthPath array of next authentication paths (AUTHPATH+)
   * @param keep keep array for the authPath algorithm
   * @param currentTreehash treehash for authPath algorithm of current tree
   * @param nextTreehash treehash for authPath algorithm of next tree (TREE+)
   * @param currentStack shared stack for authPath algorithm of current tree
   * @param nextStack shared stack for authPath algorithm of next tree (TREE+)
   * @param currentRetain retain stack for authPath algorithm of current tree
   * @param nextRetain retain stack for authPath algorithm of next tree (TREE+)
   * @param nextNextLeaf array of upcoming leafs of the tree after next (LEAF++) of each layer
   * @param upperLeaf needed for precomputation of upper nodes
   * @param upperTreehashLeaf needed for precomputation of upper treehash nodes
   * @param minTreehash index of next treehash instance to receive an update
   * @param nextRoot the roots of the next trees (ROOT+)
   * @param nextNextRoot the roots of the tree after next (ROOT++)
   * @param currentRootSig array of signatures of the roots of the current subtrees (SIG)
   * @param nextRootSig array of signatures of the roots of the next subtree (SIG+)
   * @param gmssParameterset the GMSS Parameterset
   * @param digestClass An array of strings, containing the name of the used hash function and the
   *     name of the corresponding provider
   */
  public GMSSPrivateKeyParameters(
      int[] index,
      byte[][] currentSeeds,
      byte[][] nextNextSeeds,
      byte[][][] currentAuthPaths,
      byte[][][] nextAuthPaths,
      byte[][][] keep,
      Treehash[][] currentTreehash,
      Treehash[][] nextTreehash,
      Vector[] currentStack,
      Vector[] nextStack,
      Vector[][] currentRetain,
      Vector[][] nextRetain,
      GMSSLeaf[] nextNextLeaf,
      GMSSLeaf[] upperLeaf,
      GMSSLeaf[] upperTreehashLeaf,
      int[] minTreehash,
      byte[][] nextRoot,
      GMSSRootCalc[] nextNextRoot,
      byte[][] currentRootSig,
      GMSSRootSig[] nextRootSig,
      GMSSParameters gmssParameterset,
      GMSSDigestProvider digestProvider) {

    super(true, gmssParameterset);

    // construct message digest

    this.messDigestTrees = digestProvider.get();
    this.mdLength = messDigestTrees.getDigestSize();

    // Parameter
    this.gmssPS = gmssParameterset;
    this.otsIndex = gmssParameterset.getWinternitzParameter();
    this.K = gmssParameterset.getK();
    this.heightOfTrees = gmssParameterset.getHeightOfTrees();
    // initialize numLayer
    this.numLayer = gmssPS.getNumOfLayers();

    // initialize index if null
    if (index == null) {
      this.index = new int[numLayer];
      for (int i = 0; i < numLayer; i++) {
        this.index[i] = 0;
      }
    } else {
      this.index = index;
    }

    this.currentSeeds = currentSeeds;
    this.nextNextSeeds = nextNextSeeds;

    this.currentAuthPaths = currentAuthPaths;
    this.nextAuthPaths = nextAuthPaths;

    // initialize keep if null
    if (keep == null) {
      this.keep = new byte[numLayer][][];
      for (int i = 0; i < numLayer; i++) {
        this.keep[i] = new byte[(int) Math.floor(heightOfTrees[i] / 2)][mdLength];
      }
    } else {
      this.keep = keep;
    }

    // initialize stack if null
    if (currentStack == null) {
      this.currentStack = new Vector[numLayer];
      for (int i = 0; i < numLayer; i++) {
        this.currentStack[i] = new Vector();
      }
    } else {
      this.currentStack = currentStack;
    }

    // initialize nextStack if null
    if (nextStack == null) {
      this.nextStack = new Vector[numLayer - 1];
      for (int i = 0; i < numLayer - 1; i++) {
        this.nextStack[i] = new Vector();
      }
    } else {
      this.nextStack = nextStack;
    }

    this.currentTreehash = currentTreehash;
    this.nextTreehash = nextTreehash;

    this.currentRetain = currentRetain;
    this.nextRetain = nextRetain;

    this.nextRoot = nextRoot;

    this.digestProvider = digestProvider;

    if (nextNextRoot == null) {
      this.nextNextRoot = new GMSSRootCalc[numLayer - 1];
      for (int i = 0; i < numLayer - 1; i++) {
        this.nextNextRoot[i] =
            new GMSSRootCalc(this.heightOfTrees[i + 1], this.K[i + 1], this.digestProvider);
      }
    } else {
      this.nextNextRoot = nextNextRoot;
    }
    this.currentRootSig = currentRootSig;

    // calculate numLeafs
    numLeafs = new int[numLayer];
    for (int i = 0; i < numLayer; i++) {
      numLeafs[i] = 1 << heightOfTrees[i];
    }
    // construct PRNG
    this.gmssRandom = new GMSSRandom(messDigestTrees);

    if (numLayer > 1) {
      // construct the nextNextLeaf (LEAFs++) array for upcoming leafs in
      // tree after next (TREE++)
      if (nextNextLeaf == null) {
        this.nextNextLeaf = new GMSSLeaf[numLayer - 2];
        for (int i = 0; i < numLayer - 2; i++) {
          this.nextNextLeaf[i] =
              new GMSSLeaf(digestProvider.get(), otsIndex[i + 1], numLeafs[i + 2]);
          this.nextNextLeaf[i].initLeafCalc(this.nextNextSeeds[i]);
        }
      } else {
        this.nextNextLeaf = nextNextLeaf;
      }
    } else {
      this.nextNextLeaf = new GMSSLeaf[0];
    }

    // construct the upperLeaf array for upcoming leafs in tree over the
    // actual
    if (upperLeaf == null) {
      this.upperLeaf = new GMSSLeaf[numLayer - 1];
      for (int i = 0; i < numLayer - 1; i++) {
        this.upperLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i], numLeafs[i + 1]);
        this.upperLeaf[i].initLeafCalc(this.currentSeeds[i]);
      }
    } else {
      this.upperLeaf = upperLeaf;
    }

    // construct the leafs for upcoming leafs in treehashs in tree over the
    // actual
    if (upperTreehashLeaf == null) {
      this.upperTreehashLeaf = new GMSSLeaf[numLayer - 1];
      for (int i = 0; i < numLayer - 1; i++) {
        this.upperTreehashLeaf[i] =
            new GMSSLeaf(digestProvider.get(), otsIndex[i], numLeafs[i + 1]);
      }
    } else {
      this.upperTreehashLeaf = upperTreehashLeaf;
    }

    if (minTreehash == null) {
      this.minTreehash = new int[numLayer - 1];
      for (int i = 0; i < numLayer - 1; i++) {
        this.minTreehash[i] = -1;
      }
    } else {
      this.minTreehash = minTreehash;
    }

    // construct the nextRootSig (RootSig++)
    byte[] dummy = new byte[mdLength];
    byte[] OTSseed = new byte[mdLength];
    if (nextRootSig == null) {
      this.nextRootSig = new GMSSRootSig[numLayer - 1];
      for (int i = 0; i < numLayer - 1; i++) {
        System.arraycopy(currentSeeds[i], 0, dummy, 0, mdLength);
        gmssRandom.nextSeed(dummy);
        OTSseed = gmssRandom.nextSeed(dummy);
        this.nextRootSig[i] =
            new GMSSRootSig(digestProvider.get(), otsIndex[i], heightOfTrees[i + 1]);
        this.nextRootSig[i].initSign(OTSseed, nextRoot[i]);
      }
    } else {
      this.nextRootSig = nextRootSig;
    }
  }