Nicholas Allen's Indigo Blog

Windows Communication Foundation From the Inside

September, 2006

  • Nicholas Allen's Indigo Blog

    ROT 128 Stream Upgrade Sample, Part 3

    • 4 Comments
    Last time, we built the binding element for the stream upgrade sample. The job of the binding element was to stash itself away in the binding context so that the transport could later pull out the stream upgrade and build the provider. This time we'll look at the implementation of the stream upgrade provider.

    The stream upgrade provider needs to do three things:

    1. Build the upgrade initiator for the client side of the connection. The initiator gets the remote address and via of the connection so that we can differentiate behavior based on where the connection is actually going.
    2. Build the upgrade acceptor for the server side of the connection. The acceptor and initiator pieces are the first time we have asymmetry in this simple example. Fundamentally, the initiator and acceptor use a request-reply exchange regardless of the shape of the contract or connection. This means that you're always going to get asymmetry at least at this level.
    3. Run any part of the protocol that happens independently from making the individual connections. These actions go in the Open, Close, and Abort methods of the provider. I've given all of these empty implementations because this sample doesn't need to do anything here. If you had resources allocated at pre-connect time, such as a socket connection, you would do the allocation and deallocation in these methods.
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Channels;

    namespace Microsoft.ServiceModel.Samples
    {
    class OpenAsyncResult : CompletedAsyncResult
    {
    internal OpenAsyncResult(AsyncCallback callback, object state)
    : base(callback, state)
    {
    }
    }

    class CloseAsyncResult : CompletedAsyncResult
    {
    internal CloseAsyncResult(AsyncCallback callback, object state)
    : base(callback, state)
    {
    }
    }

    class ROT128StreamUpgradeProvider : StreamUpgradeProvider
    {
    public ROT128StreamUpgradeProvider(ROT128StreamUpgradeBindingElement element, BindingContext context)
    : base(context.Binding)
    {
    }

    public override StreamUpgradeAcceptor CreateUpgradeAcceptor()
    {
    return new ROT128StreamUpgradeAcceptor(this);
    }

    public override StreamUpgradeInitiator CreateUpgradeInitiator(EndpointAddress remoteAddress, Uri via)
    {
    return new ROT128StreamUpgradeInitiator(this, remoteAddress, via);
    }

    protected override void OnAbort()
    {
    }

    protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
    {
    return new CloseAsyncResult(callback, state);
    }

    protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
    {
    return new OpenAsyncResult(callback, state);
    }

    protected override void OnClose(TimeSpan timeout)
    {
    }

    protected override void OnEndClose(IAsyncResult result)
    {
    }

    protected override void OnEndOpen(IAsyncResult result)
    {
    }

    protected override void OnOpen(TimeSpan timeout)
    {
    }
    }
    }

    I've used the AsyncResult class from our SDK samples so that I don't have to keep implementing these myself. I'm going to be using a contract-based client and server in this example, which calls the asynchronous code paths by default. I've also added the helper class as an attachment to this post.

    Next time: ROT 128 Stream Upgrade Sample, Part 4

  • Nicholas Allen's Indigo Blog

    ROT 128 Stream Upgrade Sample, Part 2

    • 5 Comments

    Building a stream upgrade for ROT 128 starts with creating a binding element to put in the channel stack. This binding element extends the special StreamUpgradeBindingElement base class, which functions very similarly to the specialized binding element base classes for transports and message encoders. We then need to override the channel factory and listener build processes because the stream upgrade binding element does not actually generate a channel. Stream upgrades are handled internally by the transport if it supports them.

    using System;
    using System.ServiceModel.Channels;

    namespace Microsoft.ServiceModel.Samples
    {
    public class ROT128StreamUpgradeBindingElement : StreamUpgradeBindingElement
    {
    internal static string ROT128UpgradeType = "application/rot128";

    public ROT128StreamUpgradeBindingElement()
    : base()
    {
    }

    protected ROT128StreamUpgradeBindingElement(ROT128StreamUpgradeBindingElement copyFrom)
    : base(copyFrom)
    {
    }

    public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
    {
    context.BindingParameters.Add(this);
    return context.BuildInnerChannelFactory<TChannel>();
    }

    public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
    {
    context.BindingParameters.Add(this);
    return context.BuildInnerChannelListener<TChannel>();
    }

    public override StreamUpgradeProvider BuildClientStreamUpgradeProvider(BindingContext context)
    {
    return new ROT128StreamUpgradeProvider(this, context);
    }

    public override StreamUpgradeProvider BuildServerStreamUpgradeProvider(BindingContext context)
    {
    return new ROT128StreamUpgradeProvider(this, context);
    }

    public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
    {
    context.BindingParameters.Add(this);
    return context.CanBuildInnerChannelFactory<TChannel>();
    }

    public override bool CanBuildChannelListener<TChannel>(BindingContext context)
    {
    context.BindingParameters.Add(this);
    return context.CanBuildInnerChannelListener<TChannel>();
    }

    public override BindingElement Clone()
    {
    return new ROT128StreamUpgradeBindingElement(this);
    }

    public override T GetProperty<T>(BindingContext context)
    {
    return context.GetInnerProperty<T>();
    }
    }
    }

    The only other important task when writing a stream upgrade binding element is to build your stream upgrade provider when asked by the transport. ROT 128 works the same on both the client and server so I've made those methods do exactly the same thing. The stream upgrade provider for this sample isn't going to care which end of the connection it is running on. Stream upgrade construction uses a pull model. Stream upgrade providers aren't required to build anything until specifically asked to generate either the acceptor or initiator. Your stream upgrade just needs to wait for the appropriate method calls to be made.

    Next time: ROT 128 Stream Upgrade Sample, Part 3

  • Nicholas Allen's Indigo Blog

    ROT 128 Stream Upgrade Sample, Part 1

    • 7 Comments

    The mission for the next five days is to build and demonstrate an implementation of a stream upgrade. For review, a stream upgrade is a component that plugs into the transport and rewrites the byte stream as it goes on and off of the network. Stream upgrades are stackable and composable. You add stream upgrades by including stream upgrade binding elements in the desired order in the binding. I went over the basics of stream upgrades a few weeks ago. Here are the articles in that series:

    1. Stream Upgrades, Part 1
    2. Stream Upgrades, Part 2
    3. Stream Upgrades, Part 3

    The example I've picked out is a stream upgrade that applies ROT 128 (ROTate by 128). ROT 13 is a famous example of a Caesar cipher that occludes messages by replacing letters in the English alphabet with the letter that is 13 places higher. When you go past 'Z', you wrap back around to 'A'. Since there are 26 letters, applying ROT 13 twice returns a letter back to where it started. ROT 128 is the equivalent for a single byte value.

    Here is the stream class that I want to have my messages run through. It includes some debugging so that we can see the messages as they go in and out.

    using System;
    using System.IO;

    namespace Microsoft.ServiceModel.Samples
    {
    class ROT128Stream : Stream
    {
    Stream stream;

    public ROT128Stream(Stream stream)
    {
    this.stream = stream;
    }

    public override bool CanRead
    {
    get { return this.stream.CanRead; }
    }

    public override bool CanSeek
    {
    get { return this.stream.CanSeek; }
    }

    public override bool CanWrite
    {
    get { return this.stream.CanWrite; }
    }

    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    this.stream.Dispose();
    }
    else { this.stream.Close();
    }
    base.Dispose(disposing);
    }

    public override void Flush()
    {
    this.stream.Flush();
    }

    public override long Length
    {
    get { return this.stream.Length; }
    }

    public override long Position
    {
    get
    {
    return this.stream.Position;
    }
    set
    {
    this.stream.Position = value;
    }
    }

    static void DumpBuffer(byte[] buffer, int offset, int count)
    {
    int pos = 0;
    while (pos < count)
    {
    int lineCount = count - pos;
    if (lineCount > 15)
    {
    lineCount = 15;
    }
    for (int linePos = 0; linePos < lineCount; linePos++)
    {
    Console.Write(" {0:X2}", buffer[offset + pos + linePos]);
    }
    for (int linePos = 15 - lineCount; linePos >= 0; linePos--)
    {
    Console.Write(" ");
    }
    for (int linePos = 0; linePos < lineCount; linePos++)
    {
    byte item = buffer[offset + pos + linePos];
    if (item < 0x20 || item >= 0x80)
    {
    Console.Write(".");
    }
    else { Console.Write((char)item);
    }
    }
    Console.WriteLine();
    pos += lineCount;
    }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
    int result = this.stream.Read(buffer, offset, count);
    Console.WriteLine("[READ] {0} bytes", result);
    DumpBuffer(buffer, offset, result);
    for (int pos = 0; pos < result; pos++)
    {
    buffer[pos + offset] ^= 0x80;
    }
    return result;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
    return this.stream.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
    this.stream.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
    Console.WriteLine("[WRITE] {0} bytes", count);
    DumpBuffer(buffer, offset, count);
    byte[] encodedBuffer = new byte[count];
    for (int pos = 0; pos < count; pos++)
    {
    encodedBuffer[pos] = (byte)(buffer[pos + offset] ^ 0x80);
    }
    this.stream.Write(encodedBuffer, 0, count);
    }
    }
    }

    Next time: ROT 128 Stream Upgrade Sample, Part 2

  • Nicholas Allen's Indigo Blog

    September CTP Released

    • 0 Comments

    Windows Vista released an interim build over the weekend to let customers track the bug fixes made after RC1. The corresponding version of WCF for this release is being called the September CTP. If you've just installed RC1, then it's probably not a high priority to upgrade unless you have a known problem that you think is fixed. If you haven't upgrade in a while, this represents the most current public release.

    To be different from RC1, this time the Orcas CTP is available on time but the Windows SDK is late.

    Here are the download materials:

  • Nicholas Allen's Indigo Blog

    Reader Survey Outcomes

    • 0 Comments

    As expected, the Monday post did not happen due to the server maintenance running a few hours long and clobbering the window for queuing the post. Unfortunately, the maintenance was for upgrading the Community Server version and that failed, so there's the possibility of more down time in the future. I'm failing back to my alternate, alternate plan, which is to just get the posts out one day at a time and not worry about it too much.

    The reader survey is unofficially closed. I don't mind having suggestions continue to come in the future. I'm calling these survey outcomes rather than survey results because I didn't ask for any quantitative measurements. These are just ideas for how to make things better that I picked out of the responses. Almost everyone liked the current format so I'm not going to change anything about post frequency or size.

    • More categories for tagging posts. I want to keep this at a reasonable number for manageability. I've currently got 17 categories, so I'll add categories that make sense but keep the total number under 25 for now.
    • Build a table of contents. This was a really good suggestion because several other people complained that posts were hard to find. I'll tie this into the new categories that get created. I won't start doing this until after the server gets upgraded again to avoid broken links.
    • Turning some of the multi-part series into long articles after they're done. I like to prioritize getting new content out but I realize that there are people that have not read all 180 posts and need help to catch up. This would eat the time slot for doing a normal post but I wouldn't do this more often than once every few weeks.
    • More articles that tell you how to solve problems. I actually tried posting these kind of articles for a week and it ended up taking too much time because most problems are either way too short or way too long. It was a lot of research and editing. I can't do anything about the long problems, but I may post two articles at once if they're very short.

    I can't make any promises about covering new topic areas. I like to write a lot of background before I go in-depth on a subject. I've already done 20 security posts, which is a solid month if they were all in a row. It's not practical to be doing that three of four times over at the same time. I started with channels and transports but since then I've added bindings, HTTP, message encoders, security, and TCP/IP. Every six to eight weeks I can probably take a week off from the normal schedule and do something totally new.

  • Nicholas Allen's Indigo Blog

    Math Behind the RSA Algorithm

    • 2 Comments

    This post is to tie up some loose ends in regards to actually performing the RSA computations. I've avoided including too much math in the earlier posts to make them easier to read. Here are some references that help explain the individual steps.

    The algorithm starts with generating n, a product of large primes, and e, the encryption exponent. Large primes are typically found by generating large random numbers and testing whether they're probably prime. It's easy to eliminate the random numbers that are obviously not prime, such as multiples of small primes, leaving only a few hundred tests necessary to find a 1024-bit or 2048-bit random prime number. The encryption exponent is frequently a fixed, small value, such as 65537. Using e = 3 used to be relatively popular because the exponentiation step becomes very cheap, but we've seen how this is sometimes dangerous.

    The decryption exponent, d, is the modular inverse of the encryption exponent. Modular inverses can be found using the Euclidean algorithm.

    Messages are encrypted by exponentiating the plain text message with the encryption exponent.

    M' = Me mod n

    Messages are chunked into fixed-size blocks to make them easier to work with. Messages are decrypted by exponentiating the encrypted message with the decryption exponent.

    M'd mod n = (Me mod n)d mod n = Me*d mod n

    For both of the large primes that make up n, we can use Fermat's Little Theorem to show that Me*d = M modulo the prime number. We can then use the Chinese Remainder Theorem to combine these congruences and show that Me*d = M mod n.

    Next time: ROT 128 Stream Upgrade Sample, Part 1

  • Nicholas Allen's Indigo Blog

    Potentially No Post Monday

    • 0 Comments

    There is some server maintenance scheduled for Sunday night, which may interfere with the normal early Monday morning blog post. I had the reader survey results and the first part of the stream upgrade sample planned for Monday. Those may happen Tuesday instead. Since Monday is already doubled up, I don't want to try to throw the original Tuesday post at you as well. If that happens, what I'll do is recover the missing day by editing the stream upgrade sample to span four days instead of five.

  • Nicholas Allen's Indigo Blog

    A More Recent RSA Attack

    • 3 Comments

    One of the interesting things about writing articles ahead of time is that the plan sometimes changes when it's time to publish the articles. It turns out that in the last few weeks someone has found an interesting forgery attack on RSA signatures. This isn't a totally general forgery attack because like one of the attacks we saw yesterday, it primarily affects RSA keys with small exponents. Unlike the attacks yesterday, this isn't a protocol failure because it relies on the signature verification algorithm having a bug. However, it turns out that the bug required is actually a pretty easy one to make.

    This new attack is from Daniel Bleichenbacher and it relies on signature verifiers not correctly interpreting an invalid PKCS message chunk. We saw earlier what the contents of the block are supposed to look like

    0x00 0x01 0xff ... 0xff 0x00 hash

    This hash field is actually a combination of some metadata and the computed hash value. Inside the metadata is a length field that tells you how long the computed hash value is. The bug is that some implementations allow garbage data inside the message chunk after the hash is complete. In that case, the block looks like

    0x00 0x01 0xff ... 0xff 0x00 metadata hash garbage

    If the RSA exponent is small, such as e = 3, then the attacker can manipulate the garbage data to make the value be a perfect cube. The attacker can then compute the cube root to construct a signature value that the validator will accept. This attack gets extremely less likely as the exponent gets larger.

    A good reference on this attack is Hal Finney's summary of the Bleichenbacher talk.

    Next time is the last article on security for a while before we get back to stream upgrades.

    Next time: Math Behind the RSA Algorithm

  • Nicholas Allen's Indigo Blog

    Reminder: 2006 Reader Survey

    • 0 Comments

    If you haven't taken the time to complete the reader survey, please help out by doing that this week. I've already gotten some cool ideas from the feedback and it's to your advantage to tell me what you like and don't like. The incoming rate has started to slow down a bit. My goal was to get 50 responses by the end of the week. If I get that many by tomorrow night, then I won't have to bug you again on Friday! Thanks to everyone that has already filled out the survey.

  • Nicholas Allen's Indigo Blog

    Attacks on RSA

    • 5 Comments

    RSA has several weaknesses called protocol failures. Protocol failures are not actually an exploit in the RSA algorithm. Instead, a protocol failure occurs when you perform inadvisable actions that give the attacker more information than they would otherwise have. The most common attack that results from a protocol failure is a direct mathematical attack that does not rely on breaking the normal strong point of RSA, the difficulty of factoring the product of two large prime numbers. Instead, the mathematical attack uses additional information from the protocol failure to bypass the protection without having to find the factorization.

    Today, I'll talk about two protocol failures that occur when you send the message multiple times with different RSA parameters n and e.

    The common modulus failure occurs when you send the same message M with the same modulus n but different values for the encryption exponent e. Suppose you send the message once with the exponent e and again with the exponent f. If e and f have no common factors, which is the case when both are prime numbers, then you can use the Euclidean algorithm to find values r and s where e*r + f*s = 1. The e and f values were public, so anyone can compute r and s. You've sent the encrypted values Me mod n and Mf mod n over the wire. Unfortunately now, (Me mod n)r*(Mf mod n)s=Me*r+f*s mod n=M mod n, so it turns out to be quite trivial to figure out what the original message value was.

    The small exponent failure occurs when you send the same message M with the same exponent e but different values for the modulus n. While the previous attack needed two messages, this attack needs e messages making it relatively hard to pull off if e is not a small value. Each message you send on the wire looks like Me mod ni for different moduluses ni. Using the Chinese Remainder Theorem, you can compute a value M' such that M' is simultaneously congruent to Me modulo n1 and n2 and all the way up to ne. Since M must be smaller than each ni for RSA to work, Me is smaller than the product of all the ni's, and therefore M' is not just congruent to Me but exactly equal to it. The modulus is larger than the number we're trying to reduce so it has no effect. Figuring out the original message then simply requires taking the e-th root of M'.

    Next time: A More Recent RSA Attack

  • Nicholas Allen's Indigo Blog

    Using RSA for Signing Messages

    • 6 Comments

    A nice property of RSA is that if we swap the role of the encryption and decryption keys, it's still possible to transmit messages. That's because the computation (Me)d mod n is the same as (Md)e mod n. Typically, messages are encrypted with your public key, which means that only a person with your private key can read the message. Anyone can pick up your public key and send you a message. Turning that around, you're the only person that can send someone else a message using your private key. However, anyone can pick up your public key and decrypt that message. This allows us to prove who the sender of the message is to the same accuracy as protecting the contents of the message.

    To save space, it's not necessary to sign the entire message with your private key. Instead, you can take a hash function for which it is difficult to find collisions and sign the hashed version of your message. This allows you to create a fixed-length signature for use with arbitrarily long messages.

    Signing is not compatible with the algorithm presented yesterday for chunking messages. Each chunked message for encryption contains randomly-generated padding bytes. This means that the signature would unpredictably change every time we tried to recompute the message. Signing uses a padding block where every byte of padding has the value 0xff. To make sure that you know which type of padding is being used, the block type for signing is 0x01 instead of the block typeof 0x02 for encryption. The contents of a block look like

    0x00 0x01 0xff ... 0xff 0x00 hash

    The same private key should not be used for both signing and encrypting messages. Generate multiple key pairs in that situation to prevent information attacks where an attacker has access to messages signed by both the public and private keys.

    Next time: Attacks on RSA

  • Nicholas Allen's Indigo Blog

    2006 Reader Survey

    • 2 Comments

    As promised, today I'm putting out a survey to collect some of your feedback about the last six months of blogging. I decided to not go with a site like SurveyMonkey to let you be more freeform about your responses. Answer as many of the questions as you'd like. Everything is optional. I expect most people will complete this in 5-10 minutes. When you go to submit your survey, either use the email contact form or respond with a comment. I've turned on moderation for all comments on this post.

    The survey runs through Saturday and I'll announce any changes that result next Monday. I'll continue reading any responses that come in after Saturday if you want to send them but they won't be a part of the announced results. It will be interesting to see how many people respond. The average article last month got accessed about 7000 times over RSS and another few thousand times over the Web. I may be doing a lot of reading this weekend or it may just turn out that you're all automated spam bots. I used to get a few dozen spam comments a day even with the site filtering turned on until I disabled comments on all posts older than 2 weeks.

    1. Tell me something interesting about yourself. Maybe you just want to give your name, rank, and serial number or maybe you want to go into more detail. This will help me figure out who you are at conferences and events. If you have a blog, this is the right question to tell me where it is.
    2. Tell me why you're interested in WCF. Or, tell me why you read this blog if you're not interested in WCF. Please don't include any confidential information. It's okay to say that you're working on secret projects at an undisclosed company so you can't give any details.
    3. The current format is a new post every official Microsoft business day, with the average post being 300 to 500 words in length. Do you like this format? Do you want to see longer posts that come out less frequently? This is the question to talk about the posting schedule.
    4. Do you like the visual style? I don't have total control over the layout of the sidebar or articles but I did pick the color scheme, fonts, and some of the arrangement. Actually, you can see exactly what I've customized by looking at the CSS file. Have you seen something nice on another blog that I should steal?
    5. Name one topic that you'd love to see less often.
    6. Name one topic that you'd love to see more often.
    7. Name one blog I should be reading. If you told me about your blog in the first question, you don't have to list it again here. I covered some of the blogs I read in My Blogging Dirty Dozen post.
    8. Tell me about the other sources of information you use to learn about WCF. Blogs, forums, web sites, door-to-door salesmen, anything at all. In particular, tell me if you read our community site or forums.
  • Nicholas Allen's Indigo Blog

    Splitting Messages for RSA

    • 7 Comments

    For your particular pair of RSA primes, there is a fixed size to the messages that can be encrypted with the product, n, of those primes. During decryption, you will always end up with the smallest positive integer message that satisfies the algorithm. That means that the value of your message has to be smaller than the value n to be unique. With a 1024 bit product of primes, you can only send a 1024 bit message. On the other hand, if the message value is too small, such that the modulus operation during encryption doesn't do anything, then cracking the message becomes much easier. This means that each message should be approximately the same size but slightly smaller than n. Like many other problems, this is a job for message chunking.

    There is a defined standard for chunking RSA messages included in PKCS #1 (Public Key Cryptography Standard #1). There's been several versions of the standard due to discovered vulnerabilities. I'll use the original version since it's the simplest but obviously you should not be using this version in your applications today.

    If your value of n is k-bits long, then each block is going to be k/8 bytes long. The contents of a block look like

    0x00 0x02 padding 0x00 data

    The 0x02 stands for the block type. We'll look at another block type tomorrow for use when signing messages instead of encrypting. The padding is then eight or more random non-zero bytes. The padding bytes prevents people from attempting to guess the original text and encrypting with the public key to check their guess. With padding, you would need to guess both the plain text and the random bytes, which can be made more expensive than attempting to crack the product of primes. During decryption, the padding is stripped off by starting from the third byte and scanning until the first non-zero byte. The data consists of the remaining bytes in the message.

    The padding requirement means that there's a minimum of 11 bytes overhead in each chunk. For 1024 bit chunks, that works out to roughly 1 byte of overhead per 10 bytes of actual data.

    Next time: Using RSA for Signing Messages

  • Nicholas Allen's Indigo Blog

    No Real Post Today

    • 0 Comments

    I was going to post a survey today to collect some reader feedback, but I decided it would be better to make it a larger production and give people all next week to send in responses. The normal posting schedule will still take place. That means you'll get both the survey plus the next post on transport security Monday morning.

    In the meantime, keep trying out RC1 and let us know about any problems you run into right away.

  • Nicholas Allen's Indigo Blog

    Using RSA for Sending Messages

    • 4 Comments

    One of the key points made about the Diffie-Hellman algorithm is that it doesn't actually allow you to send a message from one party to another. DH is useful for constructing a new shared secret value but can't directly be used to exchange an existing secret. The alternative that is typically used for exchange is RSA (named after the inventors Ronald Rivest, Adi Shamir, and Leonard Adleman). A lot of people spell the last one as Adelman, which as far as I can tell is incorrect.

    The idea of RSA is very similar to an earlier cipher called Pohlig-Hellman. RSA requires the recipient to publish two numbers, called n and e, in a directory with their identity. The n and e values play a very similar role as the group values p and g from DH. The value n is actually the product of two large prime numbers, called x and y, that the recipient keeps secret. The evidence we have is that the easiest way to break RSA is to factor n back into the primes x and y. This means that the security that the system provides is equivalent to the amount of work required to perform the factorization. This is again analogous to the security of DH provided through the difficulty of deriving the private keys A and B.

    To send a message M with RSA, the sender first retrieves n and e from the directory. The sender then computes Me mod n and sends that value over the wire. Call the encrypted value M'. The recipient computes a value d such that d*e = 1 mod (x – 1) and d*e = 1 mod (y – 1). It isn't obvious how to efficiently compute this d, but it turns out to not be expensive using a variation of the Euclidean algorithm. The recipient then computes M'd mod n, which reverses the encryption and returns the original value M. No one else can find the d to do this unless they can factor out x and y first.

    The similarities between DH and RSA don't stop at the description. The size of the RSA primes you need to protect your message M is roughly the same as the DH prime you need to protect your exchanged key. This means that I don't need to repeat the article on configuring the algorithm. Instead, I'll go off in a different direction and talk about how to chunk a large message into multiple M values for use with RSA.

    Next time: Splitting Messages for RSA

  • Nicholas Allen's Indigo Blog

    Attacks on Diffie-Hellman

    • 3 Comments

    We're going to continue looking at the Diffie-Hellman algorithm today by examining how to configure the algorithm to be more resistant to attacks. DH is small enough that I'm not going to summarize the algorithm here. You can go back to the description yesterday if needed. I'll reuse the same letters g and p for continuity.

    The values g and p are exchanged publicly, perhaps by putting them into a public certificate. There are two modes of DH depending on whether the generated keys for a particular g and p combination are reused. Static DH reuses the key values. Using static keys is faster and doesn't really give any aid to an attacker that can precompute data. Ephemeral DH makes up a new set of keys for every transaction. The advantage of ephemeral keys is that they can be thrown away afterwards and even breaking into the machine later can't help you recover what was exchanged. The sender and receiver can use different modes so ephemeral-static DH is an example with an ephemeral sender and static receiver.

    The other major choice when configuring DH is how big to make p and the private keys. In general, it's easier to attack p than to attack a private key. This means that p requires more bits than a private key does. Further, the private key needs to be longer than the key that is being constructed through DH. I have seen rules of thumb that the private key should be twice as long as the exchanged key and that a 1024 bit prime p has an effective limit of a 160 bit private key. This means that a 1024 bit prime is really only good for safely constructing about an 80 bit key, smaller than the 112 bits of 3DES. You should be doing some independent reading about the DH algorithm if you actually need to pick the appropriate size of p and other desirable mathematical properties.

    The good news is that suites like SSL combine selected modes of DH with other techniques to protect against common attacks, such as man-in-the-middle while starting up the conversation. That means that your security does not require understanding any of this.

    Next time: Using RSA for Sending Messages

  • Nicholas Allen's Indigo Blog

    Diffie-Hellman Key Exchange

    • 10 Comments

    If you've been reading the previous posts on network security, then you've seen several instances where two parties need a shared secret. We've just been assuming that a shared secret is magically known. How can two parties share a secret without having previously arranged confidential information between them? This is the boot-strapping problem of encryption, because it seems like exchanging a secret requires that you've exchanged secrets before. However, it turns out that two parties can build a shared secret even if all of the communication between them can be intercepted.

    Diffie-Hellman (DH) is an algorithm that lets two parties collectively create an encryption key. You can't directly use DH to send data from one party to another. DH lets you create an encryption key, and then you can use that key to send the data. In DH, there are two public numbers for the conversation, a shared public key for each side, and a hidden private key for each side.

    To start a key exchange, the two sides first share a large prime number p and a base value g that is between 1 and p - 1. These numbers can be agreed on in public, so there's no need to protect the conversation from eavesdroppers. This allows the exchange to start without having a prearranged secret. Each side then picks a secret value that doesn't get shared. Call the two sides and their corresponding numbers A and B. A sends gA mod p over to side B. B sends gB mod p over to side A. The values sent over the wire are still totally public. This relies on the fact that even when g, p, and the result are publicly known, it's still very difficult to compute A or B.

    A knows the value A and gB mod p, making it simple for A to calculate gAB mod p. B knows the value B and gA mod p, making it simple for B to calculate gAB mod p. Anyone else would be unable to compute this value, making it possible to use this shared result as an encryption key. How difficult is it to compute gAB mod p given g, p, gA mod p, and gB mod p? That actually isn't known, although all evidence so far points to it being quite challenging.

    Next time: Attacks on Diffie-Hellman

  • Nicholas Allen's Indigo Blog

    Stream Upgrades, Part 3

    • 3 Comments

    Today's the final part of the series on the stream upgrade model (StreamUpgradeBindingElement and StreamUpgradeProvider were covered previously). I've got a sample of a stream upgrade to show next week but I figured that everyone would like a little break from the topic before jumping into that. The rest of this week has topics about transport security.

    When we left off with the StreamUpgradeProvider, there were two methods on that class for creating an initiator and an acceptor. The initiator and acceptor are paired components for negotiating the upgrade and transforming the data stream. Let's start by looking at the initiator.

    public abstract class StreamUpgradeInitiator
    {
    protected StreamUpgradeInitiator();

    public abstract IAsyncResult BeginInitiateUpgrade(Stream stream, AsyncCallback callback, object state);
    public abstract Stream EndInitiateUpgrade(IAsyncResult result);
    public abstract string GetNextUpgrade();
    public abstract Stream InitiateUpgrade(Stream stream);
    }

    Every time GetNextUpgrade is called, it returns an opaque string that specifies an upgrade type that this initiator supports. The upgrade types will be tried successively until the initiator indicates that it has no more types to attempt by returning null. The upgrade type string typically looks something like a MIME type and most initiators will only have one type to try. The SSL stream security and Windows stream security upgrades use application/ssl-tls and application/negotiate, respectively. After an upgrade is accepted, InitiateUpgrade is used in either its synchronous or asynchronous form to actually transform the data stream.

    The acceptor side looks virtually the same as the initiator side.

    public abstract class StreamUpgradeAcceptor
    {
    protected StreamUpgradeAcceptor();

    public virtual Stream AcceptUpgrade(Stream stream);
    public abstract IAsyncResult BeginAcceptUpgrade(Stream stream, AsyncCallback callback, object state);
    public abstract bool CanUpgrade(string contentType);
    public abstract Stream EndAcceptUpgrade(IAsyncResult result);
    }

    Each time the initiator proposes an upgrade type, CanUpgrade on the acceptor is called with that type string. The acceptor then says yes or no to performing the upgrade. AcceptUpgrade is the exact equivalent to InitiateUpgrade for transforming the data stream.

    The stream upgrade model has been stable over the last few months. The most significant change was to add the Via parameter so that the provider can make upgrade decisions based on both the next and final hops.

    Next time: Diffie-Hellman Key Exchange

  • Nicholas Allen's Indigo Blog

    Stream Upgrades, Part 2

    • 5 Comments

    The stream upgrade model consists of four abstract base classes. We looked at the StreamUpgradeBindingElement yesterday. Since stream upgrades don't have a corresponding channel, the only purpose of the binding element is to notify the transport that this binding is interested in having a potential stream upgrade available. If the transport does not support stream upgrades, then it will ignore this request and the stream upgrade binding element will go unhandled. It is up to the transport to at some point initialize the stream upgrade.

    The other three parts of the stream upgrade model are the StreamUpgradeProvider, StreamUpgradeInitiator, and StreamUpgradeAcceptor. The binding element is responsible for creating the provider. The provider is then responsible for creating the initiator and acceptor as needed. We'll look at the provider today and look at the initiator and acceptor tomorrow.

    public abstract class StreamUpgradeProvider : CommunicationObject
    {
    protected StreamUpgradeProvider();
    protected StreamUpgradeProvider(IDefaultCommunicationTimeouts timeouts);

    protected override TimeSpan DefaultCloseTimeout { get; }
    protected override TimeSpan DefaultOpenTimeout { get; }

    public abstract StreamUpgradeAcceptor CreateUpgradeAcceptor();
    public abstract StreamUpgradeInitiator CreateUpgradeInitiator(EndpointAddress remoteAddress, Uri via);
    }

    Although stream upgrades aren't channels, the provider shares the Open, Close, and Abort functionality of ICommunicationObject. In Open, the provider takes care of any work that needs to be completed prior to being able to offer an upgrade. For example, a security stream upgrade might use the call to the Open method to allocate credentials or certificates that the local endpoint will present as its identity. The Close and Abort methods allow the provider to clean up any resources allocated in Open or in the created upgrades.

    Take note of the fact that nothing related to the initiator or acceptor has a timeout parameter. The only timeouts on the provider are on the methods that come from ICommunicationObject. This does not mean that you have an unlimited amount of time to complete operations. Stream upgrades are run as part of a larger bounded operation, such as a receive, and you simply don't know how much of that time slice is remaining. This is an unfortunate part of the model, but it also encourages you to frontload as much work as possible into the startup of the provider.

    Next time: Stream Upgrades, Part 3

  • Nicholas Allen's Indigo Blog

    Stream Upgrades, Part 1

    • 7 Comments

    The next several posts are about the stream upgrade model for modifying the byte stream output of a transport. I'll use these posts to cover the basic elements of the stream upgrade model, take a break for a while to talk about some other topics, and later have a sample that shows building a stream upgrade from scratch.

    A stream upgrade takes the output from message serialization and replaces that byte stream with another byte stream. Stream upgrades are represented in the channel stack by a binding element that doesn't actually create a channel. It is legal to have more than one stream upgrade in the channel stack and active at the same time. These stream upgrades chain sequentially so that the stream output of one is passed as the stream input to the next one. Our primary use of stream upgrades is to provide transport security by replacing the unencrypted stream with an encrypted stream. You could also use stream upgrades for tasks such as compression, character re-encoding, or byte reordering.

    public abstract class StreamUpgradeBindingElement : BindingElement
    {
    protected StreamUpgradeBindingElement();
    protected StreamUpgradeBindingElement(StreamUpgradeBindingElement elementToBeCloned);

    public abstract StreamUpgradeProvider BuildClientStreamUpgradeProvider(BindingContext context);
    public abstract StreamUpgradeProvider BuildServerStreamUpgradeProvider(BindingContext context);
    }

    Building a client or server StreamUpgradeProvider is very similar to constructing a ChannelFactory or ChannelListener for a particular channel. The StreamUpgradeProvider class will be the topic of tomorrow's post.

    Since there's no channel corresponding to the stream upgrade, the transport is the part of the channel stack that's responsible for actually creating and using the stream upgrade. This means that stream upgrades are only going to be supported by certain transports. Our named pipe and TCP transports, the connection-oriented transports, both support stream upgrades. These transports provide connections that flow undelimited streams of bytes, meaning that they mesh well with the stream upgrade model. Our HTTP transport does not support stream upgrades.

    Applying a stream upgrade to a connection is optional. The stream upgrades included in the channel stack represent the maximum collection of upgrades that can be used with a connection. The client and server sides have to negotiate and agree on the collection of stream upgrades that will be used for a particular collection. The process for negotiation is covered in a later post.

    Next time: Stream Upgrades, Part 2

  • Nicholas Allen's Indigo Blog

    You Must Understand This

    • 1 Comments

    WCF allows you to customize the collection of message headers sent with a request, including defining your own custom headers. Message receivers tend to be very loose about the messages that they accept and they typically will silently ignore any headers that they don't understand. However, this is a bad thing to have happen when your custom message header is intended to change the semantics of an operation.

    The solution to this problem in SOAP is the mustUnderstand attribute. The mustUnderstand attribute is a qualifying tag to the message header stating that the receiver must either successfully process the message header or fail the operation. Use of the mustUnderstand attribute can help you when versioning your service. After a version upgrade, there is a potential for miscommunication between clients and servers that have different versions. If you add new headers to your messages, such that calls will still complete for an older version but the meaning of those calls has changed, then marking the relevant message headers as mustUnderstand will change this soft failure to a hard failure. Making the call fail makes it much easier to detect the problem than if the result is silent data corruption.

    You can control the mustUnderstand attribute for your messages through the MessageHeader attribute in your MessageContract on the client. The contract shown here is based on one automatically generated by svcutil.exe.

    [DebuggerStepThrough()]
    [GeneratedCode("System.ServiceModel", "3.0.0.0")]
    [MessageContract(WrapperName = "MyMessageContract")]
    public partial class MyMessageContract
    {
    [MessageHeader(Namespace = "http://tempuri.org/", MustUnderstand = true)]
    public string importantHeader;

    [MessageBodyMember(Namespace = "http://tempuri.org/", Order = 0)]
    public string body;

    public MyMessageContract()
    {
    }

    public MyMessageContract(string importantHeader, string body)
    {
    this.importantHeader = importantHeader;
    this.body = body;
    }
    }

    This causes the generated message to have the mustUnderstand attribute be set.

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
     <s:Header>
      <h:importantHeader s:mustUnderstand="1" xmlns:h="http://tempuri.org/">
       header
      </h:importantHeader>
     </s:Header>
     <s:Body>
      <MyMessageContract xmlns="http://tempuri.org/">
       <body>
        body
       </body>
      </MyMessageContract>
     </s:Body>
    </s:Envelope>
    

    Next time: Stream Upgrades, Part 1

  • Nicholas Allen's Indigo Blog

    Building a Composite Duplex Binding Element

    • 1 Comments

    I occasionally get requests to help people build what turns out to be a variation of our CompositeDuplexBindingElement. Composite duplex is just a channel shape changer that supports both reading and writing, and has independence between the connections on the two sides. The basic binding element for this shape changer really does not contain any deep functionality. If you need to build a similar type of shape changer, you can get most of the way there by doing only four things.

    1. Override CanBuildChannelFactory and CanBuildChannelListener to delegate down to the underlying bindings on the factory and listener sides. You'll want to explicitly validate the TChannel shape parameter against the shapes that your composite duplex supports before delegating.
    2. Override BuildChannelFactory and BuildChannelListener to delegate down to the underlying bindings on the factory and listener sides. You need some way of distinguishing the addresses of the two sides. If each side has its own transport and protocol scheme, they'll resolve to separate base addresses on your service host and avoid a conflict. If the two sides have the same protocol scheme, then they'll pick up the same base address. The BindingContext has an explicit override mechanism that you can use for the address of the listener side.
    3. Override GetProperty to have a meaningful resolution order. GetProperty returns a single value. If you have a different collection of property settings on the listener and factory sides, you need to pick one to be the winner when both want to return a query result.
    4. Consider the impact of your shape changing on metadata and security. Underneath of your binding element, the channel stack is going to be forked into two connections. This is generally going to cause problems for anyone that assumes that the endpoint you receive messages from is the same as the endpoint you write messages to. That may break guarantees, such as the ISecurityCapabilities, of underlying channels. You need to explicitly correct the guarantees that are being advertised through GetProperty.

    Next time: You Must Understand This

  • Nicholas Allen's Indigo Blog

    Hey Look! WCF RC1 is Done

    • 3 Comments

    The RC1 release of WCF is done and only very shortly after the end of August. There are very few new features or compatibility breaking changes in this release. The big differences you should notice are improvements to the reliability and performance of the product. Maybe you'll want to upgrade your applications to this new release candidate to make sure everything is ready for the final version?

    Here are the download materials:

    Update: All of the downloads should be working now.

  • Nicholas Allen's Indigo Blog

    Finding Your Upgrade Path

    • 1 Comments

    One day, the official first version of WCF will be completed and released. Lots of people are not just waiting around for that day to come and have already built lots and lots of applications on top of prerelease versions of WCF. Everyone will want to upgrade to the final release when it comes out from the beta versions that they're using now. As someone who has spent far too much time lately porting code from one version to another, I've been thinking about the techniques I've tried to make the upgrade process between versions easier.

    1. Know what version of WCF the code was written against. Once you know the version that you were using, you can start looking up the changes that have happened since then. This seems obvious, but it's harder than it sounds due to the very frequent CTPs and other releases. If you can't remember the version that was used for a piece of code, you can sometimes guess from the WinFX dll version in the project references or the approximate date you wrote the code. I've tried to find the recent release dates and versions.
      • December 2005 CTP (2.0.50727.151 - 12/19/2005)
      • January 2006 CTP (2.0.50727.154 - 01/17/2006)
      • February 2006 CTP (3.0.50727.358 - 02/21/2006)
      • Vista Beta 2 (3.0.03906.22 - 05/23/2006)
      • June 2006 CTP (3.0.04131.06 - 06/23/2006)
      • July 2006 CTP (3.0.04307.00 - 07/17/2006)
      • Vista RC1 (3.0.04324.17 - 09/01/2006)
      Anything significantly before the start of this year is probably in very bad shape these days.
    2. Try to get your code working on the June 2006 CTP or later. The June CTP is the earliest release that is somewhat similar to what the final release is going to look like. Trying to go from anything earlier to a current release will most likely result in a lot of compilation errors. If you do much of the heavy porting work now, it will be that much easier to port to the final release at some point.
    3. When you can't figure out how to resolve a compilation error, try checking the breaking changes list. The community site has breaking changes back through the January 2006 CTP.
    4. If your service exports metadata, grab a copy before and after porting to make sure that nothing about your public service contract has been inadvertently changed.
    5. Take performance measurements, especially throughput, before and after porting. You should expect to generally see the same or better performance moving to the latest version. A significant drop in throughput may indicate that you're hitting a throttle that you were not hitting previously. We have changed some of the default throttle values in just about every release. High turnaround time or dropped connections but low CPU usage is often a sign of a throttle problem (assuming you haven't bottlenecked the network or disk or something). You can collect an end-to-end trace that shows when throttles are hit, although the throttle traces are made at the Information level so you'll get a lot of messages to dig through.
    6. If you are explicitly setting configuration values, check whether the default values of those configuration settings have changed. Actually, check the default values of configuration settings even if you are using the default value. The default values for message encoders and transports are set pretty conservatively. You will need to figure out reasonable values for your application. In general, applications that send big messages will want to significantly increase the size of quota settings and timeout values. Applications that have small messages but lots of concurrent users will want to leave the settings where they are or possibly even decrease them slightly.
    7. We have spent a lot of time improving error messages. This will hopefully help.
Page 1 of 1 (24 items)