General – Landon Hemsley https://landonhemsley.com Digital Elegance Delivered Fri, 04 Jun 2021 21:29:42 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.2 130243796 Breaking Counter Mode Encryption https://landonhemsley.com/breaking-counter-mode-encryption/ Fri, 04 Jun 2021 21:29:34 +0000 https://landonhemsley.com/?p=270 The subject of today’s post is breaking counter mode encryption, which directly concerns three cryptopals challenges: challenge 19, challenge 20, and challenge 25. (And maybe more … I’m only as far as challenge 25 at this point.)

What is counter mode encryption? Counter mode encryption is a method of encryption in which the content of a message itself is subjected to an XOR binary mathematical operation against an encrypted stream of bytes. It’s called counter mode because the non-encrypted stream of bytes is simply a unique nonce paired up with a counter that is incremented, encrypted, and chained over and over again. Wikipedia has a great summary of what it is.

Look at the image at the top of this post. That’s the algorithm. Can you spot any weaknesses?

In the three previously mentioned challenges, the task is to decrypt a ciphertext without knowing the key. If you look carefully at that image, it should be relatively obvious that there are two weaknesses.

  • The block cipher is deterministic. If you can figure out what the nonce and counter is, you can produce the same keystream. That’s usually pretty hard if it’s done right, but it’s still a weakness.
  • If you can figure out what the keystream is (regardless of the nonce, counter and key), then you can figure out the plaintext. After all, the plaintext is just an XOR of the ciphertext and the keystream.

In challenges 19 and 20, multiple messages are built using the exact same keystream. This is a no-no. If you encrypt several messages with the same keystream, it becomes relatively simple to figure out the keystream. After all, for a single character in a message, there are only 256 possible bytes against which the message can be XOR’d to produce the cipher text. When you know that the same character different characters (say the first one) in several different messages were built via XOR against the same byte of keystream, then you can find the keystream by trying all 256 bytes and taking what you consider the “best one.”

How to find the best one? In challenge 19, they ask you to primarily use trial and error. Cycle through all 256 a few times for the first few columns, review the results, try some more bytes, and make more substitutions.

In challenge 20, they tell you to do this programmatically. Remember ETAOIN SHRDLU? Frequency analysis on each individual first, second, third, nth character in each of these messages is how I determined which was the best.

public abstract class AbstractFrequencyAnalyzingCTRKeyDeterminer {
    //without knowing the key, can we derive the keystream?
    // ciphertext block XOR keystream block = plaintext block
    // since we have the cipher text block, we just have to figure out what to xor against these texts to make them
    // legible

    final Chi chi = new Chi();
    final XOR xor = new XOR();

    public abstract void additionalManualTweaks(final byte[][] ciphertexts, final byte[] keyStream);

    public byte[] findTheKeyStream(final byte[][] ciphertexts) {
        //inefficient, but find the longest cipher length
        int maxLen = Arrays.stream(ciphertexts)
                .map(b -> b.length)
                .max(Integer::compareTo)
                .orElseThrow();

        byte[] keyStream = new byte[maxLen];

        //get a column of letters in cipher text
        // gracefully pass by ciphertexts without letters in the column under examination
        for (int l = 0; l < keyStream.length; l++) {
            final byte[] temp = new byte[ciphertexts.length];

            int count = 0;
            for (byte[] ciphertext : ciphertexts) {
                if (l < ciphertext.length) {
                    temp[count] = ciphertext[l];
                    count++;
                }
            }
            final byte[] byteColumn = new byte[count];
            System.arraycopy(temp, 0, byteColumn, 0, count);
            keyStream[l] = determineKeyByte(byteColumn);
        }

        //this function will manually place characters to resolve the full keystream
        additionalManualTweaks(ciphertexts, keyStream);

        return keyStream;
    }
   
    /**
    *  use chi-squared scores to find the "best" byte for the key
    */
    private byte determineKeyByte(final byte[] byteColumn) {
        //get the most likely first byte, but print them all

        double lowestChiScore = Double.MAX_VALUE;
        Integer winner = null;
        for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
            char[] xordFirstLetters = xor.singleKeyXOR(byteColumn, i);
            double localChi = chi.score(xordFirstLetters);
            if (localChi < lowestChiScore) {
                lowestChiScore = localChi;
                winner = i;
            }
        }

        assert winner != null;
        return (byte) winner.intValue();
    }
}

In challenge 25, they give you a new tool. They say, “Hey! You can now edit the original message via an edit function!” They tell you to build the keystream, encrypt the new text against the appropriate keystream bytes, and overwrite the original message. Then, if you decrypt the message, you’ll find your text beginning at the appropriate offset.

    public void edit(final byte[] cipherText, final int offset, final String newText) {
        // get keystream of length offset plus newText.length rounded up to block size
        final LittleEndianNonce nonce = new LittleEndianNonce();
        final int blockLength = nonce.get().length;
        final int newLength = ((newText.length() + offset) / blockLength) * blockLength + blockLength;
        final int numOfBlocks = newLength / blockLength;
        final byte[] keystream = new byte[newLength];
        for (int block = 0; block < numOfBlocks; block++) {
            var encryptedNonce = ecb.AES(nonce.get(), CipherMode.ENCRYPT);
            System.arraycopy(encryptedNonce, 0, keystream, block * encryptedNonce.length, encryptedNonce.length);
            nonce.increment();
        }

        //get the portion of the keystream we actually care about
        final byte[] ktext = new byte[newText.length()];
        System.arraycopy(keystream, offset, ktext, 0, newText.length());

        // overwrite the ciphertext
        var newTextBytes = newText.getBytes();
        var sub = xor.multiByteXOR(newTextBytes, ktext);
        System.arraycopy(sub, 0, cipherText, offset, sub.length);
    }

But this is a fatal flaw. XOR has a property that dooms whoever thinks this might have been a good idea: XOR-ing a text against all zeros (and I mean binary zero –> [00000000], not character zero, which is actually 48 in binary –> [00110000]) leaves the original text. So, if you edit a ciphertext such that the entire ciphertext is overwritten with zeros, you’ll get the unaltered keystream.

    /**
     * plaintext can be anything. Find an ascii art and use that if you want.
     */
    @Test
    void recoverThePlainText() {
        final String plaintext = getPlainTextFromFile();
        final byte[] cipherText = ctr.encrypt(plaintext);
        /*------------------------------------------*/

        //we can get the keystream out of the edit function by
        // passing in all 0s
        final String breakerString = new String(new byte[cipherText.length]);

        //copy the cipherText so we retain original
        final byte[] keystream = ArrayUtils.clone(cipherText);

        //edit the copy with the breaker string to get the keystream
        ctr.edit(keystream, 0, breakerString);

        //once we have the keystream, we can simply xor it against the cipherText to recover the plaintext
        final String broken = new String(xor.multiByteXOR(cipherText, keystream));

        assertEquals(plaintext, broken);
    }

Game over.

Of these three challenges, I probably enjoyed challenge 20 the most. It took me a bit to figure out that I could treat the set of messages they provided as a matrix, where every column in the matrix was XOR’d against the same character. Once I figured that out, it just became a single character XOR and frequency analysis. Challenge 25 was way too obvious, and I didn’t have the patience to sit there poking and plugging at challenge 19. I solved challenge 20 first, and then applied my solution to challenge 19.

Thanks for reading! -LH

]]>
270
Cloning a Mersenne Twister Random Number Generator from its output https://landonhemsley.com/cloning-a-mersenne-twister-random-number-generator-from-its-output/ https://landonhemsley.com/cloning-a-mersenne-twister-random-number-generator-from-its-output/#comments Wed, 26 May 2021 17:38:13 +0000 https://landonhemsley.com/?p=258 As was said in my last post, I’m doing cryptopals. Just last night I finished Challenge 23. I was able to successfully clone a 32-bit Mersenne Twister pseudorandom number generator (PRNG) from its output. You can see how I did this by checking out my solution in my github repo.

If you’re like me when first looking at this, you probably are overwhelmed. So, I thought I would take a moment to try to explain how and why this works. I can’t do this, though, without acknowledging this blog post and its author. It was incredibly helpful in understanding how to reverse the tempering function of the mersenne twister.

Also, I want to address the question posed in the original problem:

How would you modify MT19937 to make this attack hard? What would happen if you subjected each tempered output to a cryptographic hash?

Let’s get going…

Preface

What’s interesting about the mersenne twister is that the PRNG retains an array within that manages the generator’s state. It has to do this in order to ensure that it doesn’t start repeating numbers. The period of a PRNG is how long it takes before the generator starts repeating numbers, and the primary perk to this particular PRNG is that it has a super long period: 2^19937-1 . (That’s a huge number.)

When the PRNG gives you a “random number,” it pulls a number out of its state array and subjects that number to “tempering.” What that means is that the number is subjected to several bitwise mathematical operations, and is then returned. Here’s what that looks like in the version of the twister that I implemented. (The capital letters are constants … Pay attention to the two private functions.)

    /**
     * temper a value
     * @param untempered the value to be tempered
     * @return the tempered value
     */
    int temper(int untempered) {
        int y = temperRightShift(untempered, U, D);
        y = temperLeftShift(y, S, B);
        y = temperLeftShift(y, T, C);
        y = temperRightShift(y, L, FULL_MASK);
        return y;
    }

    private int temperRightShift(final int y, final int shift, final int mask) {
        return y ^ ((y >>> shift) & mask);
    }

    private int temperLeftShift(final int y, final int shift, final int mask) {
        return y ^ ((y << shift) & mask);
    }

There are two “versions,” so to speak, of transformation: a left shift operation and a right shift operation. In both cases, the original value is subjected to a bit shift, then and’d against a mask, and then xor’d against the original.

What’s not obvious

If you haven’t yet, you really should go check out this article. If you have, I’m going to try to do this in a way that is perhaps a bit clearer than he put it. I’m going to use the number -252645136, which when written out in binary, looks like this.

1111 0000 1111 0000 1111 0000 1111 0000

Nice and easy to see what’s going on when the number pattern is super obvious. Let’s perform and then undo the third transformation using this number: y := y xor ((y << s) and b), where y is our number, s is the shifting constant 7, and b is the bitmask 0x9D2C5680.

Let’s start with the first operation: Shift our number 7 digits to the left and AND it against b. Let’s call the result y’. An asterisk is an original part of the number, and a – is something that came in as a result of a shift.

                                
  **** **** **** **** **** **** *--- ----     
  0111 1000 0111 1000 0111 1000 0000 0000  <-- 7-bit shift left
& 1001 1101 0010 1100 0101 0110 1000 0000  <-- 0x9D2C5680
-----------------------------------------
  0001 1000 0010 1000 0101 0000 0000 0000  <-- y'

Gonna pause there before i do the next operation. Look at the last 7 bits of y’. It’s all 0s. If you’ve ever done XOR before, you know that XOR-ing something against 0 will leave you with what you started with. It’s the same as AND-ing something against a 1. No change. And, the reason that those figures are 0 is because of the shift. (If the original number ended in all 1’s, the last 7 bits of the shifted number would still all be 0. For this reason, I said 7 bits and not 12.)

This means a piece of the original number is going to remain in our final result. That is important, but it’s not super obvious!

Let’s do the next operation: XOR the result against the unmodified original. Let’s call the result z, like bloglien does.

  1111 0000 1111 0000 1111 0000 1111 0000  <-- y
X 0001 1000 0010 1000 0101 0000 0000 0000  <-- y' 
-----------------------------------------
  1110 1000 1101 1000 1010 0000 1111 0000  <-- z

Now, to undo this. If you didn’t know this, I should say that XOR is reversible. q XOR r = t and t XOR r = q. This means that all we have to do recover the original is recover y’.

But how can we do that? y’ is gone once the operation is done. Is it recoverable?

Yes. yes it is, but only because you retain a piece of the original y in z. That’s what’s not obvious in this at first glance.

Recovering y’ and y

In order to recover the original y, y’ is needed. How does this work? Bloglien calls it “waterfalling.” I call it “redoing the original operation 7 bits at a time.” As I do this, I’m going to leave out what I call “extraneous bits,” (which after masking is always 0). If they’re not of immediate concern, I’m just not going to write them. I will, however, keep them vertically aligned with the other figures. If you want to pull a piece of paper out and fill out every bit, feel free.

Step one: Mask the portion of z that contains the unaltered portion of y.

  1110 1000 1101 1000 1010 0000 1111 0000 <-- z
& 0000 0000 0000 0000 0000 0000 0111 1111 <-- mask the lowest 7 bits
-----------------------------------------
                                 111 0000 <-- what we are left with

Step two: Just like we did to the original y, shift 7 bits to the left and AND that against b (the masking constant), and poof! We have 7 bits of y’.

                        11 1000 0         <-- lowest 7 bits shifted left 7 bits
                      & 01 0110 1         <-- 7 bits of b in these positions
                      -----------
                        01 0000 0         <-- 7 bits of recovered y'

Step three: XOR the recovered y’ against z to recover 7 more bits of y.

                        10 0000 1         <-- 7 bits of z
                    XOR 01 0000 0         <-- 7 bits of recovered y'
                    -------------
                        11 0000 1         <-- 7 more bits of y

Step four: REPEAT! You have 7 more bits of y. Mask them, shift them, AND against b to recover 7 more bits of y’, and then XOR against z to recover 7 more bits of y.

               1 1000 01                  <-- masked and shifted
             & 0 1100 01                  <-- b
            ------------
               0 1000 01                  <-- recovered y'
           XOR 1 1000 10                  <-- z
           -------------
               1 0000 11                  <-- y

       1000 011                           <-- y, masked and shifted
     & 1101 001                           <-- b
     ----------
       1000 001                           <-- recovered y'
   XOR 1000 110                           <-- z
   ------------
       0000 111                           <-- recovered y

  0111                                    <-- y, masked and shifted (we lose 3 bits)
& 1001                                    <-- b
------ 
  0001                                    <-- recovered y'
X 1110                                    <-- z
------ 
  1111                                    <-- recovered y

Now, take all the bits of recovered y and concatenate them, and you get:

 1111 0000 1111 0000 1111 0000 1111 0000  <-- the original y

That’s the algorithm. Mask, shift, AND, XOR, Repeat. I could redo this for a right shift to show you how it works in the opposite direction, but it’s the same except that you retain the most significant bits of a number instead of the least significant bits. Also, the right shift is less difficult than the left because the shifting constants are larger, meaning you run out of room more quickly. (With the fourth transformation, you don’t even need to repeat. It’s one and done.)

In code

So how does “untempering” look when you put it in code? Well, pretty close to tempering, but with a few gotchas.

The first line in each unTemper function calls on a method to convert an integer into a bitmask. In other words, 7 becomes 0000 0000 0000 0000 0000 0000 0111 1111 in convertIntToRightEndMask. The definition for this can be found here.

From there, the mask is moved horizontally by shift bits, starting with 0 (since blockMaskShift starts at 0). Then we AND it against z, which allows us to get the original bits that stayed from the previous transformation all by themselves. Then we shift those bits, mask them against the constant, and XOR it against z, and repeat. It works for left or right shifts the exact same. Plug in the right inputs (which come from the MT spec), and you can undo tempering.

    int unTemper(final int tempered) {
        int y = unTemperRightShift(tempered, L, FULL_MASK);
        y = unTemperLeftShift(y, T, C);
        y = unTemperLeftShift(y, S, B);
        y = unTemperRightShift(y, U, D);
        return y;
    }

    private int unTemperRightShift(final int z, final int shift, final int maskConst) {
        final int blockMask = convertIntToLeftEndMask(shift);
        int zp = z;
        for (int blockMaskShift = 0; blockMaskShift < (W - shift); blockMaskShift += shift) {
            zp = zp ^ (((zp & (blockMask >>> blockMaskShift)) >>> shift) & maskConst);
        }
        return zp;
    }

    private int unTemperLeftShift(final int z, final int shift, final int maskConst) {
        final int blockMask = convertIntToRightEndMask(shift);
        int zp = z;
        for (int blockMaskShift = 0; blockMaskShift < (W - shift); blockMaskShift += shift) {
            zp = zp ^ (((zp & (blockMask << blockMaskShift)) << shift) & maskConst);
        }
        return zp;
    }

Clone the twister

Once you’ve got past the hard part of undoing the twister, all you need is a sample of 624 outputs from a Mersenne Twister PRNG to clone it. You just “untemper” those outputs, overwrite the PRNG’s internal state array with the untempered values, and boom. You’re done. See here.

Addressing their question

So, to go back to the authors’ original question about this…

How would you modify MT19937 to make this attack hard? What would happen if you subjected each tempered output to a cryptographic hash?

Good question.

If you subject the state value to a cryptographic hash at any point during tempering, you wipe out the original bits tied to the state value, which makes it super difficult to recover inasmuch as the cryptographic hash is super difficult to crack (which they generally are). At that point, you’d basically be left with brute force, trying at most 2^32-1 different permutations to see if an untempered value matches the cryptographic hash. This would effectively make the PRNG far more secure since you wouldn’t be able to easily undo it.

In sum, if you get rid of the original bits from the untempered inputs, then you make it super hard to recover the untempered value tied to the PRNG’s state array.

This is cool

At first, this sort of blew my mind, but as I worked through it a few times in code and on paper, it ended up being one of the most fun challenges to complete in cryptopals. That’s the reason behind this lengthy write-up: I really got excited about this problem. I hope that others are just as fun to crack in the future.

Peace! -LH

]]>
https://landonhemsley.com/cloning-a-mersenne-twister-random-number-generator-from-its-output/feed/ 2 258
How to add WS-Security to .NET Core SOAP Headers without WCF https://landonhemsley.com/how-to-add-ws-security-to-net-core-soap-headers-without-wcf/ Fri, 06 Jul 2018 23:40:15 +0000 https://landonhemsley.com/?p=149 If you’ve ever enjoyed the wonderful experience that is consuming a web service that’s at least 10 years old, odds are you’ve dealt with WS-Security headers.

If you’ve had to deal with that while developing in .NET Core, you probably have spent a great deal of time banging your head against the wall.

I had this issue recently. I was developing a front-end RESTful web service which exposed one or two select internal web service operations to the wider public. One of these operations resided on a web service that was developed several years ago; it required WS-Security headers in order to authenticate.

Lucky for me, support for WS-Security in the WCF libraries for .NET Core is non-existent. This lack of support has been a known issue since 2016, but no one appears to have been able to find the time to fix this glaring hole.

Well, it may have been fixed at some point, but that work (if it was done) was lost.

So, what do you do if native support for WS-Security headers in your soap payloads isn’t supported by the framework you’re using for your development? Write your own custom headers that serialize the XML into the SOAP Payload.

You’re trying to get this in your serialized SOAP payloads

<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
   <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-12039161">
      <wsse:Username></wsse:Username>
      <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"></wsse:Password>
    </wsse:UsernameToken>   
</wsse:Security>

You have to model out the UsernameToken object into it’s own class first. Annotate the class with the necessary XmlSerializer annotations so that when it gets serialized out, it works as it needs to.

    [XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
    public class UsernameToken
    {
        [XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
        public string Id { get; set; }

        [XmlElement]
        public string Username { get; set; }
        [XmlElement]
        public Password Password { get; set; }
    }

Then use that model in a class that inherits from the System.ServiceModel.Channels.MessageHeader class. Override the OnWriteHeaderContents method and manually serialize the XML.

    public class Security : MessageHeader
    {
        public UsernameToken UsernameToken { get; set; }

        public override string Name => this.GetType().Name;

        public override string Namespace => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";

        public override bool MustUnderstand => true;

        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(UsernameToken));
            serializer.Serialize(writer, this.UsernameToken);
        }
    }

And you’ll get a SOAP Header that does what it is designed to do … authenticate you against a crazy-old web service with an authentication scheme that isn’t supported by dotnet core… or the dotnet foundation … or anything.

 

]]>
149
Jenkins pipelines and continuous integration https://landonhemsley.com/jenkins-pipelines-and-continuous-integration/ Wed, 19 Jul 2017 13:19:52 +0000 https://landonhemsley.com/?p=94
This is Jenkins. He’s polite.
Over the last few weeks, I have been focused on improving automated deployment for java web applications using Jenkins. In particular, much of the focus has been on doing so by using the pipeline plugin.

This is a pretty great tool because it allows for automated deployment in a scripted fashion. If there’s one thing that has frustrated me, however, it is the documentation for how to use the various “steps” the pipeline script allows you to write into a deployment script. To understand, check this page of steps documentation.

My main beefs are:

  1. No examples. At all.
  2. Horrendous formatting. I frequently forget whether the type comes above or below the property I’m attempting to use.
    It’s confusing.
  3. Huge learning curve. Groovy script is cool, except that this seems not to be true Groovy script, but a sort of encapsulation in which Groovy is allowed in parts, but not in others.
  4. Basically zero documentation on the “scripted pipeline” method of doing this.

Great tool. Bad documentation. Hard to learn, but awesome once it’s learned.

]]>
94
Internet Explorer 10 & 11 do not support HTML5 drag and drop file input form submissions. https://landonhemsley.com/internet-explorer-10-11-do-not-support-html5-drag-and-drop-file-input-form-submissions/ Wed, 21 Jun 2017 20:56:27 +0000 https://landonhemsley.com/?p=84 So, I’m working on a front-end widget in asp.net mvc wherein a user is supposed to be able to upload a spreadsheet to the application I’m working on. The requirements as to the submission method for this particular form were that end users needed to be able to submit it by dragging and dropping, or by clicking a “Browse” link that would open a file upload dialog.

Drag and drop + browse to upload

Those who’ve worked with file uploads before know the HTML for this input is fairly simple: <input type="file" />

However, it’s a bit more complicated than that in this case.

Because I’m working in asp.net MVC, front-end validation is typically done in an unobtrusive fashion. Microsoft designed it so that all a dev needs to do is decorate model members with validation attributes. [Required], and the like. For this particular application, I had to design my own validation attribute to determine whether or not the file type of a submitted file is of the correct extension: [FileTypeValidation(Extensions = ".xlsx", ErrorMessage = "Submitted file must be an .xlsx file.")] (see the end for the code behind this.)

After decorating the view model with this attribute, the front-end validation methods did their job, and it became impossible for someone to submit a non-xlsx file and be able to proceed. Rather than a simple <input type="file" />, my input element became <input accept=".xlsx" aria-label="Choose File" data-val="true" data-val-filetype="Submitted file must be an .xlsx file." data-val-filetype-regex="(\.xlsx)$" data-val-required="The Spreadsheet field is required." id="UploadFile" name="Spreadsheet" tabindex="-1" type="file" value="">, and unobtrusive validation took care of the rest. Pretty standard in asp.net mvc.

However, in IE 11, it also became impossible for someone to submit the file by dragging and dropping.

Starting in IE 10, Microsoft enabled the drag and drop feature of the HTML5 file api for use by developers. This api allows developers to manipulate the DOM through drag and drop. It’s the engine behind the spiffy UI’s where, when a file is uploaded, the user instantly sees details about the file appear on the webpage. It’s incredibly useful.

On the downside, how Microsoft decided to make the default action on drop events an “open/save” action in IE 10/11. That’s all well and good, unless you don’t want that as an action on an <input type="file" /> element.

“No big deal,” you might be thinking. “I’ll just use javascript to place the file upload using that API.”

If that’s what you’re thinking, you thought wrong. The files element belonging to a drop event’s target member (event.target.files) is read-only, meaning one cannot programmatically alter what files will be submitted through the form. Only users can do that by clicking the file input and going through the file upload dialog.

So, let’s sum up: In IE 10/11, you can execute a drag and drop and have access to all of a file’s data through the file api, but you can’t actually upload the file with a drag and drop as you would if you went through the upload file dialog.

Lame sauce. Internet Explorer is total lame sauce.

How to get around this? Use the file api to save dragged and dropped files into a javascript variable. Then, on form submission, ignore the default action and build a new FormData object that can be submitted via ajax. Here’s a great tutorial on how to do this.

The caveat: Do this, and that pretty validation attribute instantly becomes useless. Totally useless.

Ultimately, the best way to get around this problem is to make another input (either text/hidden) and make the value of that only programmatically alterable. When someone submits a file, you store the filename in that input and do validation on the filename. Then, when you submit, call your validation on your inputs. If the validation passes, submit the form via ajax. (Reference that earlier tutorial.)

It was decided that the effort wasn’t worth the energy I would need to invest in order to make that happen, so I don’t have an implementation to share. Instead, I’ll share the validation attribute and the front-end jquery unobtrusive validation adapter I wrote in order to do file type validation on the <input type="file" /> element.

    //file type validation attribute - validates file types of submitted files to ensure the file

    public class FileTypeValidationAttribute : ValidationAttribute, IClientValidatable
    {
        public string Extensions {
            get {
                return string.Join(",", _extensions);
            }

            set {
                _extensions =  value.Split(',');
                //force leading period on entry for each extension
                _extensions.ToList().ForEach(e => e = (e[0] != '.') ? '.' + e : e);
            }
        }

        private string _regexString {
            get { return "(\\" + string.Join("|\\", _extensions) + ")$"; }
        }

        private string[] _regexExtensions {
            get {
                return _extensions.Select(e => "\\" + ((e[0] != '.') ? '.' + e : e) + "$").ToArray();
            }
        }

        private string[] _extensions { get; set; }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var file = (HttpPostedFileWrapper)value;
            if(file != null)
            {
                foreach (var _ext in _regexExtensions)
                {
                    if (Regex.IsMatch(file.FileName, _ext, RegexOptions.IgnoreCase)) return null;
                }
            }

            return new ValidationResult(this.ErrorMessageString);
        }

        public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var FileTypeRule = new ModelClientValidationRule {
                ErrorMessage = this.ErrorMessageString,
                ValidationType = "filetype",
            };

            FileTypeRule.ValidationParameters.Add("regex", _regexString);

            yield return FileTypeRule;
        }
    }

//the unobtrusive jquery validation adapters that enable front-end validation on the data-val-filetype* attributes of the file input element
$.validator.unobtrusive.adapters.add("filetype", ["regex"], function (options) {
    options.rules["FileTypeValidation"] = options.params.regex;
    options.messages["FileTypeValidation"] = options.message;
});

$.validator.addMethod("FileTypeValidation", function (value, element, param) {
    var patt = new RegExp(param, 'i');
    if (patt.test(value)) return true;
    else return false;
});
]]>
84
Always make sure you only have ONE localhost SSL certificate in your store https://landonhemsley.com/one-localhost-ssl-certificate-iis/ Wed, 14 Jun 2017 13:50:29 +0000 https://landonhemsley.com/?p=69 Stay in web development long enough, and eventually you’re going to need to do development work over an SSL connection. Because development work in SSL is typically done on localhost (like most development), you will need a certificate that certifies that localhost is secure. If you don’t, your browser will try to prevent you from navigating to your own locally hosted web server (which is silly since traffic never really leaves your machine).

Typically, the easiest way around this problem is to generate a “Self-signed certificate,” in which you’re basically vouching for yourself in order to satisfy browser SSL cert requirements. If you happen to be using IIS, generating a self-signed cert takes all of about 30 seconds, and storing it in Window’s trusted certificate authority repositories takes just as long.

Up until a few weeks ago, Google Chrome would take these certificates without complaint. But, with a recent update, they began requiring SANs (Subject Alternative Names) to be listed in the certificate. I happen to be using IIS 7, which doesn’t place a SAN by default. So that meant that the usual IIS certificate generation procedure became instantly worthless.

If you happen to be running on Windows 8.1 or later, powershell 4 comes with a cmdlet that allows you to generate a self-signed cert with SANs. I unfortunately am running Windows 7, however, so that cmdlet was unfortunately worthless.

So, I turned to openssl. Here are the steps I took from a linux bash in order to create a valid self-signed certificate with SAN’s.

Step 1:  Write (or copy/paste) an openssl configuration file. … I’ve put mine at the bottom of this post for your reference.

I found this configuration here and made a copy, altering some things I didn’t really understand, but muddling through it anyway. Hopefully that’s a good resource for you.

Step 2: Run this command (This command will generate an ssl certificate and a key that can be folded into a pfx that’s good for 10 years … please note the -config option pulls in the configuration we just created)

openssl req -config localhost.conf -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout localhost.key.pem -days 3652 -out localhost.cert.pem

Step 3: Check your work, if you like.

openssl x509 -in localhost.cert.pem -text -noout

Step 4: Now that you have a certificate and a private key, if you need this certificate to be stored in Windows, you’ll need to convert it to a .pfx certificate. Run this to do that.

openssl pkcs12 -inkey localhost.key.pem -in localhost.cert.pem -export -out localhost.true.pfx

Step 5: Add your certificate to your local trusted root certificate store, and ensure that your web server can serve it with HTTPS requests. (I’m afraid you’ll have to google-fu that one…)

Now, the kicker….

After I had done all these steps, I would occasionally and erratically be served protocol errors when loading localhost on Chrome. Half the time it loaded fine… half the time it didn’t. This frustrated me to no end.

It turns out that I had two certificates in my trusted root store for localhost (or at least I think I did). I had previously made a self-signed certificate straight out of IIS 7, and it was still in IIS, capable of being served on HTTPS requests, though I didn’t have it bound to any ports. After banging my head against my desk repeatedly (in a figurative sense), I finally tried getting rid of the old certificate, simultaneously clearing it out of the trusted root certificate authority store.

Haven’t had a problem since. The moral of the story? Always make sure you only have ONE localhost SSL certificate in your store.

# Self Signed (note the addition of -x509):
#     openssl req -config example-com.conf -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout example-com.key.pem -days 365 -out example-com.cert.pem
# Signing Request (note the lack of -x509):
#     openssl req -config example-com.conf -new -newkey rsa:2048 -nodes -keyout example-com.key.pem -days 365 -out example-com.req.pem
# Print it:
#     openssl x509 -in example-com.cert.pem -text -noout
#     openssl req -in example-com.req.pem -text -noout

[ req ]
default_bits        = 2048
default_keyfile     = server-key.pem
distinguished_name  = subject
req_extensions      = req_ext
x509_extensions     = x509_ext
string_mask         = utf8only

# The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
#   It's sort of a mashup. For example, RFC 4514 does not provide emailAddress.
[ subject ]
countryName         = US

stateOrProvinceName = MT

localityName        = Montana

organizationName    = Montana Interactive LLC

# Use a friendly name here because it's presented to the user. The server's DNS
#   names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
#   by both IETF and CA/Browser Forums. If you place a DNS name here, then you 
#   must include the DNS name in the SAN too (otherwise, Chrome and others that
#   strictly follow the CA/Browser Baseline Requirements will fail).
commonName          = Development Computer

emailAddress            = XXXXXXXXXXXXXX

# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
[ x509_ext ]

subjectKeyIdentifier        = hash
authorityKeyIdentifier  = keyid,issuer

#  If RSA Key Transport bothers you, then remove keyEncipherment. TLS 1.3 is removing RSA
#  Key Transport in favor of exchanges with Forward Secrecy, like DHE and ECDHE.
basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

# RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
# extendedKeyUsage  = serverAuth, clientAuth

# Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
[ req_ext ]

subjectKeyIdentifier        = hash

basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

# RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
# extendedKeyUsage  = serverAuth, clientAuth

[ alternate_names ]

DNS.1       = localhost
DNS.2       = localhost.localdomain
DNS.3       = 127.0.0.1

# IPv6 localhost
DNS.4     = ::1
DNS.5     = fe80::1
]]>
69
Thank you for visiting! https://landonhemsley.com/hello-world/ Sun, 04 Jun 2017 04:31:57 +0000 https://landonhemsley.com/?p=1 I’m very glad you’ve chosen to stop by. Since you’re here, I might as well describe what I hope to accomplish with this site, and my purpose in hosting it.

I am a web developer. I code. A lot. That normally would be enough to qualify me as a nerd. But since I’ve also got training in business, marketing and professional communication, I am an especially different kind of nerd… the kind that you might not immediately perceive as, well, nerdy.

So, what does that mean for this site? Well, it’s obviously pretty new. (And to be honest, at the time of this writing, I still haven’t finished developing this site … still so much more to be done… comments, anyone?) Right now it’s mostly a digital resume. I don’t know if I will want it to be that way forever, though.

As time goes on, I’m hopeful you’ll find some tidbits that can help you if you’re a digital DIY-er; as often as I learn something new, I intend to share it here. I also intend to share examples of my work; code snippets, finished WordPress themes for sale, as well as how to get ahold of me if you want help managing an application or need some special, custom work to be done. (I do a lot more than WordPress… I can code in 4 different languages, all of which directly apply to my Internet application work.)

I am also a human being with a family and opinions. And, since this is my personal site, you’ll probably see those topics pop up now and again in occasional posts.

Ultimately, I intend for this to not only to be a place where you can get ahold of me if you want work done, but also a resource where you can find tips and tricks if you want to try it yourself. I obviously love learning, so advice and contributions will always be welcome…

…welcome, that is, as soon as I finish the commenting part of this WordPress theme. (Coming soon…)

Thanks for reading! Y’all come back now, y’hear?

]]>
1