/// <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); }
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); }
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(); }