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 1
GET /?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