Random Thoughts (and Passwords) — Revised


Mea culpa. Ok, I screwed up. What follows is an annotated version of the blog entry I posted earlier today, annotations courtesy of Eric Lippert (the guy who actually wrote a good portion of VBScript). As Eric points out, I made a couple of glaring mistakes in my original posting. First, although the script I provided works, my explanation of how the script works was a bit off-kilter, to say the least. Eric has graciously corrected those mistakes, and I thank him for that. (Actually my first thought wasn’t to thank him, my first thought was, “Oh, yeah? Well, I’ll just take a look at his blog and point out all the mistakes he’s made.” Needless to say, I rather quickly determined I’d have to come up with a Plan B.)


 


Perhaps more important, Eric has also pointed out that I was a bit lah-de-dah in my approach to this. And he’s right: I was just trying to come up with something different to talk about (believe me, writing a blog on scripting isn’t as easy as you might think). My intention was to demonstrate the ability to generate random numbers/letters using VBScript, and I chose to use passwords as an example. That’s OK, I guess, but I should have made it clear that this was just a demonstration; if you’re running a bank Web site or something and you need to generate random passwords for real security purposes, VBScript is not exactly the best option (for reasons Eric explains). I didn’t exactly make that clear. I was actually thinking more in terms of maybe generating a temporary password that users were immediately required to change upon logging on; a pseudo-random password seemed a bit better than using the word password, as I know many people do. So why didn’t I just say that? Well, let’s just say, in the immortal words of Joe Theisman, that I’m no Norman Einstein, if you know what I mean.


 


Anyway, after drying my tears, I took the original entry and annotated it with Eric’s comments; I actually think it makes for a much more interesting read that way. In fact, maybe I should promise to write more entries that will require clarification, annotation, and outright correction; after all, that’s something I know is correct!


 


Thanks, again, Eric. (Although I’ll be watching you every step of the way, just waiting for you to make a mistake – ah, never mind. Even if you did make a mistake, I’d probably never catch it anyway.)


 


Here is the revised entry:


 


 


Microsoft is smack dab in the middle of the Puget Sound, home to both earthquakes and Bigfoot. (I’ve never actually seen a Bigfoot, but we’ve had a couple earthquakes in the past few years.) Because of that, we are constantly urged to keep emergency supplies – blankets, flashlights, bottled water, etc. – in our homes, our cars, our offices, anywhere we go. Now, I have to admit, I’m not very good at following those directions; we do have a really nice flashlight at home, but it’s kept upstairs in one of those closets I’m afraid to go into when the lights are on, let alone when the lights are off. If we ever do have a really big earthquake, or an invasion of Bigfoots, well ….


 


However, while I’m not very good at preparing for natural disasters, I am reasonably good at preparing for blog disasters. For example, when we first started this thing I wrote an entry on how to generate random passwords using VBScript. When I finished I thought to myself, “Big deal. Might as well just toss this one.” But then I remembered my emergency preparedness training and thought, “Wait a second, don’t throw that away. Someday there might be an earthquake or you might be too lazy to write something else, and then you can just use this instead.” I kinda of assumed I’d have this in my pocket for years, keeping it as a safety net. But here we are, two weeks into blogging, and I’m already using it up. But, what the heck: six months from now you’ll have forgotten all about this, and I can use it again. Now that’s being prepared.


 


Posted by Greg Stemp. One of the main reasons we started this blog was because I have the attention span of a hummingbird, and find it difficult to spend more than a few minutes at a task before I get bored and want to move on to something else. Wouldn’t it be better for me to become really good at one or two things than to be mediocre at 20 or 30 things? Sorry; I wasn’t paying attention; did you say something?


 


In addition to my restless nature, however, another reason we decided to do a blog was to give us a chance to address topics that we couldn’t really address elsewhere. Maybe these topics were too little to warrant an entire column or Webcast. Maybe we’d already covered them in some detail but now we wanted to add something we’d just learned. Or maybe they were interesting, but kind of fell out of the mainstream of system administration tasks.


 


Today’s entry fits the latter category: we’re going to show you how to use VBScript to generate random passwords. That’s potentially useful, but for once we aren’t really concerned with whether or not this helps you carry out the day-to-day chores of a system administrator; instead, it’s just kind of neat, and gives us a chance to explore one of the many facets of VBScript that we never get around to talking about. (If you’re dying to see information on how to calculate sines and cosines using VBScript, well, hey, one of these days ….)


 


So how do we generate random passwords using VBScript? Well, to begin with, we have to do this character-by-character; there’s no built-in VBScript command named GenerateRandomPassword. So let’s say we want a seven-character password. In that case, we’re going to have to randomly generate seven characters, and then string them all together into one password.


 


Of course, even that’s not entirely true: VBScript can only generate random numbers, it can’t randomly generate other characters (like, say, letters). So does that mean we’re limited to passwords composed only of numbers? Of course not. Instead, we’re gonna cheat here. As you probably know, anything you can type on a computer – letters, numbers, punctuation marks, tabs, spaces, whatever – has a corresponding ANSI value. For example, in the world of ANSI the lowercase a is a 97; the uppercase A is a 65. Pretty much all the characters used in standard English have ANSI values between 33 (!) and 126 (~).


 


How does that help us cheat? Well, VBScript has a function – Chr – that can convert an ASCII value to a standard character. For example, maybe you don’t believe me that the lowercase a is a 97 in ANSI. Well, try running this script, then, and see for yourself:


 


Wscript.Echo Chr(97)


 


See, told ya.


 


So how does that help us? Well, suppose we generate a random number between 33 and 126, and let’s suppose our random number generator returns a 48. We can then use the Chr function to turn this random number into a real, live character (in this case, the numeral 0). If we run the random number generator seven times, we’ll generate seven characters. If we string all those characters together – voila! a random password.


 


(How random are these passwords? Well, I don’t know beyond, “Pretty random.” Just for the heck of, I put the little script I’m about to show you into a loop, ran it 10,000 times, and saved it to a text file. There were no duplicate passwords in that batch of 10,000. My next experiment will be to run the script one million times to see if I can recreate the works of Shakespeare before those million monkeys typing on a million typewriters do.)


 


That’s all pretty cool and works great. Let me warn you, however, that random number generation is weird (or at least it seems that way to me). With that in mind, don’t worry about trying to figure out why we need to do some of the things we need to do in this script. Just accept things as they are, and move on with your life.


 


Eric Lippert comment. Don’t you think that’s kind of a bad attitude to encourage towards a program designed to increase enterprise security?  I tell people doing security programming the opposite — to write programs that keep your enterprise secure you need to understand absolutely everything that you are doing at a deep level, because if you don’t, you’re going to screw it up


 


 


First, let me show you the script, and then I’ll explain what’s going on in each section. (And, yes, if all you want to do is copy the script code and not have to read the rest of blog entry, then this is the time to start copying and pasting.)


 


Here’s the script:


 


intUpperLimit = 14


intLowerLimit = 7


 


Randomize  


intCharacters = Int(((intUpperLimit – intLowerLimit + 1) * Rnd) _


    + intUpperLimit)  


 


intUpperLimit = 126


intLowerLimit = 33


 


For i = 1 to intCharacters


    Randomize


    intASCIIValue = Int(((intUpperLimit – intLowerLimit + 1) * Rnd) _


        + intLowerLimit)  


    strPassword = strPassword & Chr(intASCIIValue)


Next


 


Wscript.Echo strPassword


 


We start off by setting the values of two variables, one to 14, one to 7. Why? Well, as I said before, we have to run the random number generator several times in order to get a password; that’s because it only generates one number (and thus one character) at a time. Thus we need to set up a loop that runs X number of times. If we wanted all our passwords to be the same length (say, 10 characters), we wouldn’t have to do this; we could just loop 10 times. But we want to have variable-length passwords, passwords that can be anywhere from 7 to 14 characters. And that’s where the 7 and the 14 come from.


 


After assigning values to the two variables, we call the Randomize statement. Why? Well, believe it or not, it’s possible to configure the random number generator so it returns the same number every time (in other words, a completely non-random number). Why would you want to do that? I have no idea.


 


Eric Lippert comment. There are lots of reasons.  Here’s one.  Ever played FreeCell?  You can type in a “game number” and play the same game over and over again.  If you get stuck, for example, and want to come back and try it again tomorrow. 


 


The game number is simply the seed to the RNG that generates the deck.  You want to be able to generate the same deck every time, even though it is “random”.


 


Another example Imagine a world where you couldn’t reliably reproduce random sequences:  You have a sort algorithm.  The tester wonders how it behaves on random lists.  So they generate a few million random lists, and uh oh, one of them bluescreened the machine.  Bummer.  I guess we’ll never see THAT sequence of random numbers again… 


 


There are many other situations in which you want a predictable sequence of pseudo-random numbers; those are just a couple.


 


But to prevent that from happening, you need to “seed” the random number generator each time you call it (that is, give it a different starting point).


 


Eric Lippert comment. No, you only need to call Randomize _once_, not once per call to Rnd.  Once the system has been seeded, each random number generated acts as the seed for the NEXT call to Rnd.  The RNG has been cleverly designed so that it does not go into short loops.


 


In fact, you MUST only call Randomize once.  Doing so in a loop, as you are doing, makes the random number sequence LESS random, not MORE random.  Why’s that?  Read on!


 


The Randomize function seeds the random number generator by passing it the current system time, a nifty little trick considering the fact that – in this dimension anyway – each moment in time is unique.


 


Eric Lippert comment. Now this is a crucial error, in several ways.


 


First,  every moment in time is not unique.   First off, the statement is trivially untrue, as the timer gives the number of seconds gone by today.  The moment in time “exactly noon, 30 December 1996” has exactly the same timer value as “exactly noon” every other day.


 


Second, you have not taken the granularity into account.  The system timer is only accurate to the nearest millisecond, which means that two times that differ by less than a millisecond often do not get unique numbers.  But worse, VBScript rounds off the timer to a float, for some unknown reason.  There are 86.4 million milliseconds in a day, but only 23 bits of mantissa in a float, and 2^23 is less than 8.4 million!  So the timer can’t possibly be accurate to more than ten milliseconds.


 


That means that if there are two calls to a timer-based Randomize in the same tenth of a second, the randomizer gets the same value.


 


Fortunately, we considered this possibility when we wrote the Randomize method.  Actually what the Randomize method does is it computes a new seed based on 16 bits from the timer and the previous seed, where the Rnd method changes the seed.  But even so, this is adding very little entropy to the mix.  Calling Randomize frequently makes the sequence of random numbers not really much harder to guess.  (Ironically, the faster the machine gets, the less entropy Randomize adds, as there is much higher likelihood that any two operations will hit the same 10 ms window.)


 


I would not recommend calling Randomize more than once per program.  If you think you need to, to add more entropy, then you need to consider using a more buff RNG.


 


That brings us to the most important problem with your algorithm.  An attacker who possesses one randomly generated password can deduce the other randomly generated passwords from it if this algorithm is used to batch-generate many passwords at once.


 


All the attacker needs to know is your algorithm and one of the passwords.  As I mentioned before, there are fewer than 8.3 million possible seeds.  Suppose the attacker gets password kWiJiBo.  The attacker first writes a loop that resets the machine’s timer to each of the 8.3 million possible seeds, and determines which ones return “k” as the first generated letter.  Fewer than 1% of them will, so now there are only 80000 seeds to check to see which one return kW as the first two generated letters.  That reduces the problem down to about 800, and pretty soon the attacker knows EXACTLY what the random number seed was at the time his password was generated.  (Thanks to all your calls to Randomize, the attacker can also deduce what the system time was when his password was generated, which might be interesting information.)


 


The fact that you’ve thrown so many extra Randomize calls in there makes the attacker’s job slightly harder, as there’s now got to be a few adjustments to the cracker algorithm to take machine timings into account, but like I said, calling Randomize doesn’t really add very much entropy to the mix.  Any attacker who knows a little basic cryptography and has a fast machine could crack this system in a few hours, and they’d then know every password generated by the system.


 


Generating random passwords safely requires considerably more buff random number generation than we provide in VBScript.  If you want to be generating random passwords, I recommend using the Crypto APIs.  Their random number generators are “true random” in the sense that it is computationally infeasible to determine the next number given the previous one.  The pseudo-random number generator is not suitable for any security application, any video game where there’s money on the line, etc. 


 


 


Ok, brace yourselves, because now comes one of the strangest looking lines of code you’ll ever see in a script:


 


intCharacters = Int(((intUpperLimit – intLowerLimit + 1) * Rnd) _


    + intUpperLimit)  


 


What in the world is going on here? Believe it or not, what we’re doing here is generating a random number (notice the Rnd function buried deep within all those parentheses), and then assigning that random number to the variable intCharacters (this is the number of characters we’re going to have in our password). We’re also using the Int function to convert the randomly-generated number to an integer; if we get a value like 99.303, we want to chop the decimal places off and end up with plain old 99.


 


The heart and soul of our line of code is shown in boldface below; this is where the random number actually gets generated:


 


intCharacters = Int(((intUpperLimit – intLowerLimit + 1) * Rnd) _


    + intUpperLimit)  


 


Weird as this looks, it’s a mathematical function that will generate random numbers between 14 (intUpperLimit) and 7 (intLowerLimit). In other words (well, in other numbers):


 


((14 – 7 + 1) * Rnd) + 14


 


Yes, we know it looks crazy. Like we said, the best thing to do is not worry about it, but just use the boilerplate code as provided. For example, what if you want to generate random numbers between 1 and 100? Then use this code:


 


intUpperLimit = 100


intLowerLimit = 1


 


Randomize  


intCharacters = Int(((intUpperLimit – intLowerLimit + 1) * Rnd) _


    + intUpperLimit)  


 


Just replace intUpperLimit and intLowerLimit as needed, and try not to lose any sleep over all those parentheses. (Or, I suppose you could try counting those parentheses as opposed to counting sheep. Whatever works best for you.) In fact, in our script, we’re going to set the value of these two variables, and then a few lines later we’re going to change the upper value to 126 and the lower value to 33. Why? Because now we want to generate random numbers between 33 and 126, numbers that correspond to our desired set of ANSI codes.


 


After calling the Rnd function, we’ll have the number of characters in our password; that might be 7, it might be 9, it might be 14. This means we can set up a loop to actually generate the password (remember, we need to call the random number function once for each character in the password). That explains this line of code:


 


For i = 1 to intCharacters


 


In other words, if our random number generator decided we’d have 11 characters in our password, intCharacters will be equal to 11,. As far as WSH is concerned, our For Loop would actually read like this:


 


For i = 1 to 11


 


Easy, huh?


 


Believe it or not, the rest is even easier. First, we call the Randomize function and we generate a random number between 33 and 126, a number we assign to the variable intASCIIValue. And then we have this line of code:


 


strPassword = strPassword & Chr(intASCIIValue)


 


What’s going on here? Remember, we’re using the Chr function to get the character equivalent of our random number; if we randomly generated a 97, then Chr will covert that to a lowercase a. We then take that lowercase a and tack it onto strPassword, a variable we are building, one character at a time, until we get our password. At this point in time, our password consists of a single character: a. Suppose on our next trip through the loop we randomly generate a 98. Chr converts that to a lowercase b, and we tack that on to strPassword; now our password string is ab. We just repeat that process X number and times, and we end up with something like this: ab5&hy1@WE.


 


Well, of course you could have gotten that same gibberish just by randomly pounding on your keyboard. But the point is, if you need gibberish like this, there’s no need for you to sit there and type it in; let a script automate the creation of gibberish for you. (A process similar to what many Hollywood screenwriters apparently do.)


 


Will you ever need to generate random numbers, let alone random passwords? Beat us. But, hey, what’s wrong with learning for the sake of learning? Remember, not everything in life has to be practical and pragmatic. (A good thing, too, seeing as how I’m neither.)


 


Eric Lippert comment. For “one off” password generation, your algorithm is just fine.  But why would you write a script for a one-off?  People write scripts for things they have to do over and over again, which is what makes me nervous about this example.


 


And of course, in the final analysis, the strength of a password needs to be correlated to the value of the property protected by it.  Would this be a good algorithm for generating hotmail passwords?  Actually, yeah, it’s not that bad.  What’s the worst that can happen?  Even if the attacker could figure out the password sequence, there are so many people signing up for hotmail every day, correlating the password with the user would be rather tricky. 


 


But enterprise administrators might generate a whole pile of passwords with an algorithm like this one for a bunch of alphabetically-sorted users.  In that situation, an evil user could figure out his coworker’s passwords, and that might be quite bad.


 


 


Comments (29)

  1. Dave Rothgery says:

    Of course this gets a little bit more complicated once you realize that some users will, for no reason that I’ve been able to discern, manually type the random password you generated for them instead of copying and pasting it. And so including characters that are easily confused with others is a bad idea, zeroes and Os are bad in random passwords, and so are ones, Is, and Ls. And anything other than numbers and letters can do funny things on a web form if you’re not careful, so we don’t want those, either.

  2. sil says:

    When I need to generate random characters, I tend to do something like:

    permittedChars = "abcdefABCDEF 012345"

    function randomPassword()

    pwd = ""

    for i=1 to passwordLength

    pwd = pwd & mid(permittedChars,int(rnd*len(permittedChars)+1),1) ‘ might have got the +1 in the wrong place there

    next

    randomPassword = pwd

    end function

    so that I can explicitly control which characters show up, and so I’m not reliant on knowing ASCII codes (which is probably good in a Unicode world).

  3. Raymond Chen says:

    "(Thanks to all your calls to Randomize, the attacker can also deduce what the system time was when his password was generated, which might be interesting information.)"

    And the fact that you use the current time to seed Randomize actually makes it EASIER to hack, if they can guess roughly what time you generated the password. This is often not hard to guess. E.g., "I sniffed traffic between these two machines at 1:35pm. I bet the password was created within the last five minutes." If you have a five minute window, that’s just 30,000 random number seeds that need to be scanned.

  4. A way to get weak, but memorable passwords is to use a dictionary to get 2 words, then throw in 4 digits, for passwords like "pie21-codeworm87". Assuming a dictionary of 32k interesting words, we get an entropy of 30 bits for the two words (15 each), plus 13.28 bits for the numbers. A total of 43.28 bits. Not much, but if you factor in the likelyhood of users remembering (and not writing it on their monitor) and that they’d be less likely to switch to something like "password", then it might pay off.

    The strength could be obviously improved with more numbers or with more words, but that’d start to negate the benefit (how many users can remember how to spell "pneumonoultramicroscopicsilicovolcanoconiosis", and a password like "spectrophotofluorometrically71-pseudopseudohypoparathyroidism54" is pretty bad :)).

  5. sil says:

    There are also plenty of algorithms around for building something that *sounds* like a word, even if it isn’t (you know, do a consonant-vowel-consonant-vowel…etc sort of approach), which makes the passwords easier to remember at the cost of the loss of more entropy.

  6. Dave Anderson says:

    You might want to test this:

    > intCharacters = Int(((intUpperLimit – intLowerLimit + 1) * Rnd) + intUpperLimit)

    It will go you password lengths in the [Upper..Upper+Lower] range, not in the expected [Lower..Upper] range.

    I believe you were shooting for

    intCharacters = Int(((intUpperLimit – intLowerLimit + 1) * Rnd) + intLowerLimit)

  7. fred fenster says:

    I thought this was interesting from Mr Lippert:

    "Don’t you think that’s kind of a bad attitude to encourage towards a program designed to increase enterprise security? I tell people doing security programming the opposite — to write programs that keep your enterprise secure you need to understand absolutely everything that you are doing at a deep level, because if you don’t, you’re going to screw it up."

    But then he goes on to say:

    "But worse, VBScript rounds off the timer to a float, for some unknown reason"

  8. Fred, Mr. Lippert wasn’t advocating VBScript for use in security. Since he’s not using it for that, unknowns are not devastating. Specifically BECAUSE some things aren’t well known in VBScript is just another reason why it shouldn’t be used for critical security functions.

  9. Eric Lippert says:

    I was being tongue-in-cheek; I do actually know.

    VBScript rounds off the timer value to a float for backwards compatibility going back to the 16 bit Windows version of Visual Basic.

    Of course, that’s begging the question. The reason why the 16 bit version did that is lost to the mists of time. That was over ten years ago. There are a number of methods in VB that return singles when they could return doubles, and the original language designers aren’t around to ask.

    But even supposing that I really didn’t know why it used a float, there’s no contradiction. I said that you have to understand WHAT a program does, not WHY some engineer built it. Anyone who wants to use VBScript’s Pseudo-RNG for security purposes needs to understand what the RNG actually does.

  10. JF says:

    Great discussion! I’ve always wondered how good Rnd() was in VBScript.

    Here’s a couple functions for generating random ASCII or hex chars. Both attempt to use CAPICOM.Utilities.GetRandom() if possible, then will fail down to Rnd() as necessary. The RandomPassword() function also guarantees a mixture of character types for complexity. The Sleep() call and multiple inefficient loopings are to avoid some of the predictability problems discussed here if CAPICOM can’t be used (or comment out the Randomize() in the function and do it once at the beginning of any scripts that use it multiple times).

    Btw, I think the scripting support work you’ve been doing is great — I recommend to others the Script Center all the time. My Linux associates are always surprised… 🙂

    Cheers,

    JF

    Function RandomPassword(iLength)

    On Error Resume Next

    Err.Clear

    If Not IsObject(oCapiUtil) Then Set oCapiUtil = WScript.CreateObject("CAPICOM.Utilities")

    If Err.Number = 0 Then

    bUseCapicom = True

    Else

    bUseCapicom = False

    WScript.Sleep(22)

    Call Randomize()

    End If

    If iLength < 4 Then iLength = 4 ‘To satisfy complexity requirements.

    Do

    sPassword = ""

    bHasUpper = False ‘Has uppercase letter character flag.

    bHasLower = False ‘Has lowercase letter character flag.

    bHasNumber = False ‘Has number character flag.

    bHasNonAlpha = False ‘Has non-alphanumeric character flag.

    bIsStrong = False ‘Assume password is not strong until tested otherwise.

    For i = 1 To iLength

    If bUseCapicom Then

    Do

    x = AscB(oCapiUtil.GetRandom(1))

    Loop Until (x <= 126) And (x >= 34)

    Else

    x = Int((((126 – 34) + 1) * Rnd()) + 34)

    End If

    If (x = 34) Or (x = 39) Then x = x – 1 ‘Eliminates two characters troublesome for scripts: ‘ and ". This is also how it is possible to get "!" as a password character.

    sPassword = sPassword & Chr(x)

    If (x >= 65) And (x <= 90) Then bHasUpper = True

    If (x >= 97) And (x <= 122) Then bHasLower = True

    If (x >= 48) And (x <= 57) Then bHasNumber = True

    If ((x >= 33) And (x <= 47)) Or _

    ((x >= 58) And (x <= 64)) Or _

    ((x >= 91) And (x <= 96)) Or _

    ((x >= 123) And (x <= 126)) _

    Then bHasNonAlpha = True

    If bHasUpper And bHasLower And bHasNumber And bHasNonAlpha Then bIsStrong = True

    Next

    Loop Until bIsStrong

    RandomPassword = sPassword

    End Function

    Function RandomHex(iLength)

    On Error Resume Next

    Err.Clear

    If Not IsObject(oCapiUtil) Then Set oCapiUtil = WScript.CreateObject("CAPICOM.Utilities")

    If Err.Number = 0 Then

    bUseCapicom = True

    Else

    bUseCapicom = False

    WScript.Sleep(22)

    Call Randomize()

    End If

    If bUseCapicom Then

    RandomHex = oCapiUtil.BinaryToHex(oCapiUtil.GetRandom(iLength))

    Else

    iLength = iLength * 2

    Do While iLength > 0

    x = Int((((70 – 48) + 1) * Rnd()) + 48)

    If ((x >= 48) And (x <= 57)) Or ((x >= 65) And (x <= 70)) Then

    RandomHex = RandomHex & Chr(x)

    iLength = iLength – 1

    End If

    Loop

    End If

    End Function

  11. Choosing a good random number seed is harder than you think.

  12. Interesting point of view, but I disagree with the ideas that VBA’s RNG cannot be used for secure applications. I beleive that as long as your algorithm is *hidden* you can generate strong ciphers.

    For example:

    if you put this random generated passwords in a matrix. (if you have 1000 passwords with 8 letter, you will have a 1000×8 matrix)

    And shuffle the letters in the matrix by selecting two elements from matrix (with VBAs poor RNG) and swapping them. And repeating this operation more than the total number of elements in the matrix.

    I think you will have a fairly *unpredictable* results.

  13. Interesting point of view, but I disagree with the ideas that VBA’s RNG cannot be used for secure applications. I beleive that as long as your algorithm is *hidden* you can generate strong ciphers.

    For example:

    if you put this random generated passwords in a matrix. (if you have 1000 passwords with 8 letter, you will have a 1000×8 matrix)

    And shuffle the letters in the matrix by selecting two elements from matrix (with VBAs poor RNG) and swapping them. And repeating this operation more than the total number of elements in the matrix.

    I think you will have a fairly *unpredictable* results.

  14. qassim says:

    hacking Passwords number for my accound number.

  15. Dating says:

    Mea culpa . Ok, I screwed up. What follows is an annotated version of the blog entry I posted earlier today, annotations courtesy of Eric Lippert (the guy who actually wrote a good portion of VBScript). As Eric points out, I made a couple of glaring mistake

  16. Weddings says:

    Mea culpa . Ok, I screwed up. What follows is an annotated version of the blog entry I posted earlier today, annotations courtesy of Eric Lippert (the guy who actually wrote a good portion of VBScript). As Eric points out, I made a couple of glaring mistake

  17. Work has been crazy lately and I haven’t had much time to work on SimpleScript. It’s a lot of work starting