What the !@#$ are you talking about?
Security is difficult to understand, cryptology doubly so. I recently read a wonderful blog post regarding 'cryptographic right answers'.
Seeing as this particular blog came from an expert in the field of cryptology implementation (et al; the developer of 'scrypt' hashing algorithm) and security (former BSD security officer), I think it is worth a read.
If your in a rush, the summary goes somewhere along the lines of 'use xyz algorithm due to the following abc strengths' and 'always use an HMAC to prevent tampering'.
Use SSL/TLS! blah blah!
Yes, I agree, however this protocol is not without its faults and weaknesses
The majority of my interest in this stems from researching methods to prevent or isolate and protect HTTP header & content in the event of a cipher downgrade, side channel, brute force, session renegotiation attack stemming from a traditional MITM or BGP routing bug presents itself.
Use oAuth! blah, blah!
This is also a very valid point and I also agree. However, leaving these fields visibly defined makes it easy in the event of a 'replay attack'.
The majority of today's HMAC use within the HTTP/HTTPS protocols get embedded within the browser response or the clients request headers as shown in figure 1 and defined in the IETF oAuth draft. The 'oauth_signature' field is clearly shown. (To test or see more examples of the oAuth header values, please visit hueniverse.com)
Figure 1GET /?abc=123 HTTP/1.1 Host: abc.com:443 Authorization: OAuth realm="https://abc.com/", oauth_consumer_key="xyz", oauth_token="456", oauth_nonce="213", oauth_timestamp="0", oauth_signature_method="HMAC-SHA1", oauth_version="2.0", oauth_signature="Q%2BuWrnEFBv8CEwtNuxn3bIdkjsY%3D"
In the event of a communications channel being compromised the 'oauth_signature' field can be easily recalculated by an attacker based on the modified contents leaving the server/client none-the-wiser that their message has indeed been modified.
While the concept of utilizing a HMAC to verify a message is not a new concept, the question arises 'How can one use an HMAC effectively in an scenario where the TLS/SSL communications channel has been compromised?'
Ok, ok you made you point, now what?!
While I realize that my proposal is not a standard or even typical solution to the above mentioned attack vectors, it should prove beneficial if and when the need presents itself.
Figure 2 is an exportable module to assist in creating a 'hidden' payload which contains a valid HMAC digest & data payload. This of course could be expanded to accommodate for the use of a 'nonce' as well as a 'timestamp' (both can be very beneficial, and recommended, when it comes to providing the utmost security from attacks).
Figure 1/* * node-dhcp-manager * * Copyright 2013 Jason Gerfen * All rights reserved. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ exports.createPayload = function(payload, digest, count) { var a = [], b = digest.split(''), iteration = count || 3, ret = [] do { a.push(payload.substring(0, iteration)) } while((payload = payload.substring(iteration, payload.length)) != "") for (var n = 0; n < a.length; n++) { if (b[n] && a[n]) { ret.push(a[n]+b[n]); } else if(b[n] && !a[n]) { ret.push(b[n]); } else if(!b[n] && a[n]) { ret.push(a[n]) } } return ret.join('') } exports.extractPayload = function(payload, size, count) { var num = count + 1 || 4, regex1 = new RegExp('.{1,'+num+'}', 'g'), data1 = payload.match(regex1), regex2 = new RegExp('.{1,'+num+'}', 'g'), data2 = payload.match(regex2), digest = [], data = [], i = 0 for (var n = 0; n < size; n++) { digest.push(data1[n].substr(count, data1[n].length)) } data2.forEach(function(item) { if (i < size) { data.push(item.substr(0, item.length - 1)) } else { data.push(item) } i++ }) return { digest: digest.join(''), payload: data.join('') } }
What does this have to do with a DH exchange?!
Patience is a virtue! To utilize this particular module please refer to figure 3 which 'simulates' a Diffie-Hellman key exchange between two parties.
Figure 3/* * node-dhcp-manager * * Copyright 2013 Jason Gerfen * All rights reserved. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ var chai = require('chai'), expect = chai.expect, should = chai.should(), crypto = require('../libs/crypto'), hs = require('../libs/handshake'), bob = crypto.init(), alice = crypto.init(), bobSecret = crypto.createSharedSecret(alice.pubKey), bobPubKey = crypto.encryptData(bobSecret, bob.pubKey), bobDigest = crypto.createDigest(bobSecret, bobPubKey), bobPayload = hs.createPayload(bobPubKey, bobDigest, 3) bobObj = hs.extractPayload(bobPayload, 128, 3), aliceSecret = crypto.createSharedSecret(bob.pubKey), alicePubKey = crypto.encryptData(aliceSecret, alice.pubKey), aliceDigest = crypto.createDigest(aliceSecret, alicePubKey) alicePayload = hs.createPayload(alicePubKey, aliceDigest, 3), aliceObj = hs.extractPayload(alicePayload, 128, 3) describe('handshake.js', function(){ describe('DH exchange', function(){ it('bob & alice must share secret', function(done){ expect(bobSecret).to.equal(aliceSecret) done() }) }) describe('create payload', function(){ it('must return valid payload', function(done){ expect(bobPayload).to.have.length(4224) expect(alicePayload).to.have.length(4224) done() }) }) describe('extract data from payload', function(){ it('must contain valid payload & digest', function(done){ bobObj.should.be.a('object') expect(bobObj).to.have.property('digest').with.length(128) expect(bobObj).to.have.property('payload').with.length(4096) aliceObj.should.be.a('object') expect(aliceObj).to.have.property('digest').with.length(128) expect(aliceObj).to.have.property('payload').with.length(4096) done() }) }) describe('verify digest', function(){ it('must contain valid digest of payload', function(done){ expect(bobObj.digest).to.equal(bobDigest) expect(aliceObj.digest).to.equal(aliceDigest) done() }) }) describe('verify keys', function(){ it('must contain matching keys from originals', function(done){ expect(crypto.decryptData(bobSecret, bobObj.payload)).to.equal(bob.pubKey) expect(crypto.decryptData(aliceSecret, aliceObj.payload)).to.equal(alice.pubKey) done() }) }) })
Shameless plug
The above code snippets come from a much larger project which can be found @ node-dhcp-manager.
No comments:
Post a Comment