Beispiel #1
0
 /// <summary>
 /// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
 /// </summary>
 /// <param name="buffer">An array of bytes. This method copies <paramref name="count"/> bytes from <paramref name="buffer"/> to the current stream.</param>
 /// <param name="offset">The zero-based byte offset in <paramref name="buffer"/> at which to begin copying bytes to the current stream.</param>
 /// <param name="count">The number of bytes to be written to the current stream.</param>
 /// <exception cref="T:System.ArgumentException">The sum of <paramref name="offset"/> and <paramref name="count"/> is greater than the buffer length. </exception>
 /// <exception cref="T:System.ArgumentNullException">
 ///     <paramref name="buffer"/> is null. </exception>
 /// <exception cref="T:System.ArgumentOutOfRangeException">
 ///     <paramref name="offset"/> or <paramref name="count"/> is negative. </exception>
 /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
 public override void Write(byte[] buffer, int offset, int count)
 {
     _hmacAlg.BlockUpdate(buffer, offset, count);
 }
Beispiel #2
0
        public void Init(BigInteger n, BigInteger d, byte[] message)
        {
            this.n = n;

            Arrays.Fill(V, (byte)0x01);
            Arrays.Fill(K, (byte)0);

            byte[] x    = new byte[(n.BitLength + 7) / 8];
            byte[] dVal = BigIntegers.AsUnsignedByteArray(d);

            Array.Copy(dVal, 0, x, x.Length - dVal.Length, dVal.Length);

            byte[] m = new byte[(n.BitLength + 7) / 8];

            BigInteger mInt = BitsToInt(message);

            if (mInt.CompareTo(n) >= 0)
            {
                mInt = mInt.Subtract(n);
            }

            byte[] mVal = BigIntegers.AsUnsignedByteArray(mInt);

            Array.Copy(mVal, 0, m, m.Length - mVal.Length, mVal.Length);

            hMac.Init(new KeyParameter(K));

            hMac.BlockUpdate(V, 0, V.Length);
            hMac.Update((byte)0x00);
            hMac.BlockUpdate(x, 0, x.Length);
            hMac.BlockUpdate(m, 0, m.Length);

            hMac.DoFinal(K, 0);

            hMac.Init(new KeyParameter(K));

            hMac.BlockUpdate(V, 0, V.Length);

            hMac.DoFinal(V, 0);

            hMac.BlockUpdate(V, 0, V.Length);
            hMac.Update((byte)0x01);
            hMac.BlockUpdate(x, 0, x.Length);
            hMac.BlockUpdate(m, 0, m.Length);

            hMac.DoFinal(K, 0);

            hMac.Init(new KeyParameter(K));

            hMac.BlockUpdate(V, 0, V.Length);

            hMac.DoFinal(V, 0);
        }
Beispiel #3
0
        public Packet MessageEncrypt(ICipherSetRemoteInfo remoteInfo, Packet inner)
        {
            CS1ARemoteInfo ri = (CS1ARemoteInfo)remoteInfo;

            var agreedValue = ECDHAgree(ri.RemotePublicKey, ri.EphemeralKeys.PrivateKey);

            // Hash the agreed key
            var hashedValue = Helpers.SHA256Hash(Helpers.ToByteArray(agreedValue, 20));

            // Fold to get the actual key for AES
            byte[] aesKey = Helpers.Fold(hashedValue);
            Random rnd    = new Random();

            // Setup and encrypt the actual data
            byte[] aesIV = new byte[16];
            rnd.NextBytes(aesIV);
            Array.Clear(aesIV, 4, 12);

            var cipher     = new SicBlockCipher(new AesFastEngine());
            var parameters = new ParametersWithIV(new KeyParameter(aesKey), aesIV);

            cipher.Init(true, parameters);

            var encryptedInner = new byte[inner.FullPacket.Length];
            BufferedBlockCipher bufferCipher = new BufferedBlockCipher(cipher);
            var offset = bufferCipher.ProcessBytes(inner.FullPacket, encryptedInner, 0);

            bufferCipher.DoFinal(encryptedInner, offset);

            // Construct the packet minus the hmac
            Packet outPacket = new Packet();

            outPacket.Body = new byte[29 + encryptedInner.Length];
            Buffer.BlockCopy(ri.EphemeralKeys.PublicKey, 0, outPacket.Body, 0, ri.EphemeralKeys.PublicKey.Length);
            Buffer.BlockCopy(aesIV, 0, outPacket.Body, 21, 4);
            Buffer.BlockCopy(encryptedInner, 0, outPacket.Body, 25, encryptedInner.Length);

            // ECDH for the hmac key using
            var idAgreedValue = ECDHAgree(ri.RemotePublicKey, Key.PrivateKey);

            // Mash on the IV for the compound key
            byte[] macKey             = new byte[24];
            byte[] idAgreedValueArray = Helpers.ToByteArray(idAgreedValue, 20);
            Buffer.BlockCopy(idAgreedValueArray, 0, macKey, 0, idAgreedValueArray.Length);
            Buffer.BlockCopy(aesIV, 0, macKey, idAgreedValueArray.Length, 4);

            // Actually hmac all the data now
            var hmac = new HMac(new Sha256Digest());

            hmac.Init(new KeyParameter(macKey, 0, 24));
            hmac.BlockUpdate(outPacket.Body, 0, 25 + encryptedInner.Length);
            byte[] mac = new byte[hmac.GetMacSize()];
            hmac.DoFinal(mac, 0);

            // Fold it up, shove it in and we're done
            var foldedMac = Helpers.Fold(mac, 3);

            Buffer.BlockCopy(foldedMac, 0, outPacket.Body, 25 + encryptedInner.Length, foldedMac.Length);

            return(outPacket);
        }
        public void Init(BigInteger n, BigInteger d, byte[] message)
        {
            this.n = n;
            Arrays.Fill(V, 1);
            Arrays.Fill(K, 0);
            byte[] array  = new byte[(n.BitLength + 7) / 8];
            byte[] array2 = BigIntegers.AsUnsignedByteArray(d);
            Array.Copy(array2, 0, array, array.Length - array2.Length, array2.Length);
            byte[]     array3     = new byte[(n.BitLength + 7) / 8];
            BigInteger bigInteger = BitsToInt(message);

            if (bigInteger.CompareTo(n) >= 0)
            {
                bigInteger = bigInteger.Subtract(n);
            }
            byte[] array4 = BigIntegers.AsUnsignedByteArray(bigInteger);
            Array.Copy(array4, 0, array3, array3.Length - array4.Length, array4.Length);
            hMac.Init(new KeyParameter(K));
            hMac.BlockUpdate(V, 0, V.Length);
            hMac.Update(0);
            hMac.BlockUpdate(array, 0, array.Length);
            hMac.BlockUpdate(array3, 0, array3.Length);
            hMac.DoFinal(K, 0);
            hMac.Init(new KeyParameter(K));
            hMac.BlockUpdate(V, 0, V.Length);
            hMac.DoFinal(V, 0);
            hMac.BlockUpdate(V, 0, V.Length);
            hMac.Update(1);
            hMac.BlockUpdate(array, 0, array.Length);
            hMac.BlockUpdate(array3, 0, array3.Length);
            hMac.DoFinal(K, 0);
            hMac.Init(new KeyParameter(K));
            hMac.BlockUpdate(V, 0, V.Length);
            hMac.DoFinal(V, 0);
        }
        /// <summary>
        /// Restore an authenticator from the serial number and restore code.
        /// </summary>
        /// <param name="serial">serial code, e.g. US-1234-5678-1234</param>
        /// <param name="restoreCode">restore code given on enroll, 10 chars.</param>
        public override void Restore(string serial, string restoreCode)
        {
            // get the serial data
            byte[] serialBytes = Encoding.UTF8.GetBytes(serial.ToUpper().Replace("-", string.Empty));

            // send the request to the server to get our challenge
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(GetMobileUrl(serial) + RESTORE_PATH);

            request.Method        = "POST";
            request.ContentType   = "application/octet-stream";
            request.ContentLength = serialBytes.Length;
            Stream requestStream = request.GetRequestStream();

            requestStream.Write(serialBytes, 0, serialBytes.Length);
            requestStream.Close();
            byte[] challenge = null;
            try
            {
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    // OK?
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        throw new InvalidRestoreResponseException(string.Format("{0}: {1}", (int)response.StatusCode, response.StatusDescription));
                    }

                    // load back the buffer - should only be a byte[32]
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (Stream bs = response.GetResponseStream())
                        {
                            byte[] temp = new byte[RESPONSE_BUFFER_SIZE];
                            int    read;
                            while ((read = bs.Read(temp, 0, RESPONSE_BUFFER_SIZE)) != 0)
                            {
                                ms.Write(temp, 0, read);
                            }
                            challenge = ms.ToArray();

                            // check it is correct size
                            if (challenge.Length != RESTOREINIT_BUFFER_SIZE)
                            {
                                throw new InvalidRestoreResponseException(string.Format("Invalid response data size (expected 32 got {0})", challenge.Length));
                            }
                        }
                    }
                }
            }
            catch (WebException we)
            {
                int code = (int)((HttpWebResponse)we.Response).StatusCode;
                if (code >= 500 && code < 600)
                {
                    throw new InvalidRestoreResponseException(string.Format("No response from server ({0}). Perhaps maintainence?", code));
                }
                else
                {
                    throw new InvalidRestoreResponseException(string.Format("Error communicating with server: {0} - {1}", code, ((HttpWebResponse)we.Response).StatusDescription));
                }
            }

            // only take the first 10 bytes of the restore code and encode to byte taking count of the missing chars
            byte[] restoreCodeBytes = new byte[10];
            char[] arrayOfChar      = restoreCode.ToUpper().ToCharArray();
            for (int i = 0; i < 10; i++)
            {
                restoreCodeBytes[i] = ConvertRestoreCodeCharToByte(arrayOfChar[i]);
            }

            // build the response to the challenge
            HMac hmac = new HMac(new Sha1Digest());

            hmac.Init(new KeyParameter(restoreCodeBytes));
            byte[] hashdata = new byte[serialBytes.Length + challenge.Length];
            Array.Copy(serialBytes, 0, hashdata, 0, serialBytes.Length);
            Array.Copy(challenge, 0, hashdata, serialBytes.Length, challenge.Length);
            hmac.BlockUpdate(hashdata, 0, hashdata.Length);
            byte[] hash = new byte[hmac.GetMacSize()];
            hmac.DoFinal(hash, 0);

            // create a random key
            byte[] oneTimePad = CreateOneTimePad(20);

            // concatanate the hash and key
            byte[] hashkey = new byte[hash.Length + oneTimePad.Length];
            Array.Copy(hash, 0, hashkey, 0, hash.Length);
            Array.Copy(oneTimePad, 0, hashkey, hash.Length, oneTimePad.Length);

            // encrypt the data with BMA public key
            RsaEngine rsa = new RsaEngine();

            rsa.Init(true, new RsaKeyParameters(false, new Org.BouncyCastle.Math.BigInteger(ENROLL_MODULUS, 16), new Org.BouncyCastle.Math.BigInteger(ENROLL_EXPONENT, 16)));
            byte[] encrypted = rsa.ProcessBlock(hashkey, 0, hashkey.Length);

            // prepend the serial to the encrypted data
            byte[] postbytes = new byte[serialBytes.Length + encrypted.Length];
            Array.Copy(serialBytes, 0, postbytes, 0, serialBytes.Length);
            Array.Copy(encrypted, 0, postbytes, serialBytes.Length, encrypted.Length);

            // send the challenge response back to the server
            request               = (HttpWebRequest)WebRequest.Create(GetMobileUrl(serial) + RESTOREVALIDATE_PATH);
            request.Method        = "POST";
            request.ContentType   = "application/octet-stream";
            request.ContentLength = postbytes.Length;
            requestStream         = request.GetRequestStream();
            requestStream.Write(postbytes, 0, postbytes.Length);
            requestStream.Close();
            byte[] secretKey = null;
            try {
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    // OK?
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        throw new InvalidRestoreResponseException(string.Format("{0}: {1}", (int)response.StatusCode, response.StatusDescription));
                    }

                    // load back the buffer - should only be a byte[32]
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (Stream bs = response.GetResponseStream())
                        {
                            byte[] temp = new byte[RESPONSE_BUFFER_SIZE];
                            int    read;
                            while ((read = bs.Read(temp, 0, RESPONSE_BUFFER_SIZE)) != 0)
                            {
                                ms.Write(temp, 0, read);
                            }
                            secretKey = ms.ToArray();

                            // check it is correct size
                            if (secretKey.Length != RESTOREVALIDATE_BUFFER_SIZE)
                            {
                                throw new InvalidRestoreResponseException(string.Format("Invalid response data size (expected " + RESTOREVALIDATE_BUFFER_SIZE + " got {0})", secretKey.Length));
                            }
                        }
                    }
                }
            }
            catch (WebException we)
            {
                int code = (int)((HttpWebResponse)we.Response).StatusCode;
                if (code >= 500 && code < 600)
                {
                    throw new InvalidRestoreResponseException(string.Format("No response from server ({0}). Perhaps maintainence?", code));
                }
                else if (code >= 600 && code < 700)
                {
                    throw new InvalidRestoreCodeException("Invalid serial number or restore code.");
                }
                else
                {
                    throw new InvalidRestoreResponseException(string.Format("Error communicating with server: {0} - {1}", code, ((HttpWebResponse)we.Response).StatusDescription));
                }
            }

            // xor the returned data key with our pad to get the actual secret key
            for (int i = oneTimePad.Length - 1; i >= 0; i--)
            {
                secretKey[i] ^= oneTimePad[i];
            }

            // set the authenticator data
            SecretKey = secretKey;
            if (serial.Length == 14)
            {
                Serial = serial.Substring(0, 2).ToUpper() + "-" + serial.Substring(2, 4) + "-" + serial.Substring(6, 4) + "-" + serial.Substring(10, 4);
            }
            else
            {
                Serial = serial.ToUpper();
            }
            // restore code is ok
            RestoreCodeVerified = true;
            // sync the time
            ServerTimeDiff = 0L;
            Sync();
        }