All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.cert.selector.MSOutlookKeyIdCalculator Maven / Gradle / Ivy

Go to download

The Bouncy Castle Java APIs for CMS, PKCS, EAC, TSP, CMP, CRMF, OCSP, and certificate generation. This jar contains APIs for JDK 1.5 to JDK 1.8. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs.

There is a newer version: 1.70
Show newest version
package org.bouncycastle.cert.selector;

import java.io.IOException;

import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.util.Pack;

class MSOutlookKeyIdCalculator
{
    // This is less than ideal, but it seems to be the best way of supporting this without exposing SHA-1
    // as the class is only used to workout the MSOutlook Key ID, you can think of the fact it's SHA-1 as
    // a coincidence...
    static byte[] calculateKeyId(SubjectPublicKeyInfo info)
    {
        SHA1Digest dig = new SHA1Digest();
        byte[] hash = new byte[dig.getDigestSize()];
        byte[] spkiEnc = new byte[0];
        try
        {
            spkiEnc = info.getEncoded(ASN1Encoding.DER);
        }
        catch (IOException e)
        {
            return new byte[0];
        }

        // try the outlook 2010 calculation
        dig.update(spkiEnc, 0, spkiEnc.length);

        dig.doFinal(hash, 0);

        return hash;
    }

    private static abstract class GeneralDigest
    {
        private static final int BYTE_LENGTH = 64;
        private byte[]  xBuf;
        private int     xBufOff;

        private long    byteCount;

        /**
         * Standard constructor
         */
        protected GeneralDigest()
        {
            xBuf = new byte[4];
            xBufOff = 0;
        }

        /**
         * Copy constructor.  We are using copy constructors in place
         * of the Object.clone() interface as this interface is not
         * supported by J2ME.
         */
        protected GeneralDigest(GeneralDigest t)
        {
            xBuf = new byte[t.xBuf.length];

            copyIn(t);
        }

        protected void copyIn(GeneralDigest t)
        {
            System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);

            xBufOff = t.xBufOff;
            byteCount = t.byteCount;
        }

        public void update(
            byte in)
        {
            xBuf[xBufOff++] = in;

            if (xBufOff == xBuf.length)
            {
                processWord(xBuf, 0);
                xBufOff = 0;
            }

            byteCount++;
        }

        public void update(
            byte[]  in,
            int     inOff,
            int     len)
        {
            //
            // fill the current word
            //
            while ((xBufOff != 0) && (len > 0))
            {
                update(in[inOff]);

                inOff++;
                len--;
            }

            //
            // process whole words.
            //
            while (len > xBuf.length)
            {
                processWord(in, inOff);

                inOff += xBuf.length;
                len -= xBuf.length;
                byteCount += xBuf.length;
            }

            //
            // load in the remainder.
            //
            while (len > 0)
            {
                update(in[inOff]);

                inOff++;
                len--;
            }
        }

        public void finish()
        {
            long    bitLength = (byteCount << 3);

            //
            // add the pad bytes.
            //
            update((byte)128);

            while (xBufOff != 0)
            {
                update((byte)0);
            }

            processLength(bitLength);

            processBlock();
        }

        public void reset()
        {
            byteCount = 0;

            xBufOff = 0;
            for (int i = 0; i < xBuf.length; i++)
            {
                xBuf[i] = 0;
            }
        }

        protected abstract void processWord(byte[] in, int inOff);

        protected abstract void processLength(long bitLength);

        protected abstract void processBlock();
    }

    private static class SHA1Digest
        extends GeneralDigest
    {
        private static final int    DIGEST_LENGTH = 20;

        private int     H1, H2, H3, H4, H5;

        private int[]   X = new int[80];
        private int     xOff;

        /**
         * Standard constructor
         */
        public SHA1Digest()
        {
            reset();
        }

        public String getAlgorithmName()
        {
            return "SHA-1";
        }

        public int getDigestSize()
        {
            return DIGEST_LENGTH;
        }

        protected void processWord(
            byte[]  in,
            int     inOff)
        {
            // Note: Inlined for performance
    //        X[xOff] = Pack.bigEndianToInt(in, inOff);
            int n = in[  inOff] << 24;
            n |= (in[++inOff] & 0xff) << 16;
            n |= (in[++inOff] & 0xff) << 8;
            n |= (in[++inOff] & 0xff);
            X[xOff] = n;

            if (++xOff == 16)
            {
                processBlock();
            }
        }

        protected void processLength(
            long    bitLength)
        {
            if (xOff > 14)
            {
                processBlock();
            }

            X[14] = (int)(bitLength >>> 32);
            X[15] = (int)(bitLength & 0xffffffff);
        }

        public int doFinal(
            byte[]  out,
            int     outOff)
        {
            finish();

            Pack.intToBigEndian(H1, out, outOff);
            Pack.intToBigEndian(H2, out, outOff + 4);
            Pack.intToBigEndian(H3, out, outOff + 8);
            Pack.intToBigEndian(H4, out, outOff + 12);
            Pack.intToBigEndian(H5, out, outOff + 16);

            reset();

            return DIGEST_LENGTH;
        }

        /**
         * reset the chaining variables
         */
        public void reset()
        {
            super.reset();

            H1 = 0x67452301;
            H2 = 0xefcdab89;
            H3 = 0x98badcfe;
            H4 = 0x10325476;
            H5 = 0xc3d2e1f0;

            xOff = 0;
            for (int i = 0; i != X.length; i++)
            {
                X[i] = 0;
            }
        }

        //
        // Additive constants
        //
        private static final int    Y1 = 0x5a827999;
        private static final int    Y2 = 0x6ed9eba1;
        private static final int    Y3 = 0x8f1bbcdc;
        private static final int    Y4 = 0xca62c1d6;

        private int f(
            int    u,
            int    v,
            int    w)
        {
            return ((u & v) | ((~u) & w));
        }

        private int h(
            int    u,
            int    v,
            int    w)
        {
            return (u ^ v ^ w);
        }

        private int g(
            int    u,
            int    v,
            int    w)
        {
            return ((u & v) | (u & w) | (v & w));
        }

        protected void processBlock()
        {
            //
            // expand 16 word block into 80 word block.
            //
            for (int i = 16; i < 80; i++)
            {
                int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
                X[i] = t << 1 | t >>> 31;
            }

            //
            // set up working variables.
            //
            int     A = H1;
            int     B = H2;
            int     C = H3;
            int     D = H4;
            int     E = H5;

            //
            // round 1
            //
            int idx = 0;

            for (int j = 0; j < 4; j++)
            {
                // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1
                // B = rotateLeft(B, 30)
                E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;
                B = B << 30 | B >>> 2;

                D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;
                A = A << 30 | A >>> 2;

                C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;
                E = E << 30 | E >>> 2;

                B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;
                D = D << 30 | D >>> 2;

                A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;
                C = C << 30 | C >>> 2;
            }

            //
            // round 2
            //
            for (int j = 0; j < 4; j++)
            {
                // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2
                // B = rotateLeft(B, 30)
                E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;
                B = B << 30 | B >>> 2;

                D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;
                A = A << 30 | A >>> 2;

                C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;
                E = E << 30 | E >>> 2;

                B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;
                D = D << 30 | D >>> 2;

                A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;
                C = C << 30 | C >>> 2;
            }

            //
            // round 3
            //
            for (int j = 0; j < 4; j++)
            {
                // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3
                // B = rotateLeft(B, 30)
                E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;
                B = B << 30 | B >>> 2;

                D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;
                A = A << 30 | A >>> 2;

                C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;
                E = E << 30 | E >>> 2;

                B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;
                D = D << 30 | D >>> 2;

                A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;
                C = C << 30 | C >>> 2;
            }

            //
            // round 4
            //
            for (int j = 0; j <= 3; j++)
            {
                // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4
                // B = rotateLeft(B, 30)
                E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;
                B = B << 30 | B >>> 2;

                D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;
                A = A << 30 | A >>> 2;

                C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;
                E = E << 30 | E >>> 2;

                B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;
                D = D << 30 | D >>> 2;

                A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;
                C = C << 30 | C >>> 2;
            }


            H1 += A;
            H2 += B;
            H3 += C;
            H4 += D;
            H5 += E;

            //
            // reset start of the buffer.
            //
            xOff = 0;
            for (int i = 0; i < 16; i++)
            {
                X[i] = 0;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy