OMA MD5 Digest ExampleThe OMA Digest is used as part of Open Mobile Alliance (OMA) Device Management (DM) [Blog]. It is used in OSGP (Open Smart Grid Protocol) encryption which uses Authenticated Encryption (AE) and which is used in TLS, SSH and IPSec. It secures the data and also proves the identity of the sending entity. Unfortunately, AE methods do often suffer from flaws. In this case it uses three methods: EN 14908 algorithm; RC4 (a stream cipher); and an OMA digest (which is a message authentication code - MAC). With OMA, the authenicating device stores a hash value, and then is challeged with a nonce string. The authenicating device then computes a new hash and sends it back. A nonce is a random value - in this case a Base-64 string - which is sent from the device which wants to authenicate the device it is communicating with.
The results are then:
Note: A nonce value of "aGVsbG8=" has been used (which is a Base-64 string of "hello". The nonce string is used as a challenge to the device to be authenticated. |
Examples
The operation for OMA DM Digest takes the ClientID and a secret password, and then creates ClientID:password. Next is we take the MD5 signature, and finally create the Base-64 value based on the output:
Base-64(MD5(clientID:secret))
For "fred" and "bert" we generate "fred:bert" which gives a result of "NPk0E5/lCFlWlycfa6ysGA=="
- Try "fred" and "bert". Try!, a message digest of: "NPk0E5/lCFlWlycfa6ysGA=="
We can also use HMAC MD5 with using the addition of a nonce value:
MD5(B64(MD5(clientID:secret)):nonce)
With this, the device which will be authenticated will store the hash of "username:password" (where the password does not need to be known). The nonce is then sent to the device to be authenticated, and the device then takes the pre-stored hash value, and adds ":" and the nonce value, and takes an MD5 hash, and converts it to a Base-64 string and send it back.
Sample code
The following implements simple digest:
public string calcOMA2(string Name, string Password) { string hash = ""; string tmp = String.Format("{0}:{1}", Name, Password); byte[] buffer = Encoding.UTF8.GetBytes(tmp); MD5 md5Hash = MD5.Create(); byte[] output = md5Hash.ComputeHash(buffer); hash = Convert.ToBase64String(output); return hash; }
The following code implements an HMAC digest:
private string calculateHash(string Name, string Password, string ServerNonce) { string hash = ""; string tmp = String.Format("{0}:{1}", Name, Password); byte[] buffer = Encoding.UTF8.GetBytes(tmp); MD5 md5Hash = MD5.Create(); // MD5(clientID:secret) byte[] output = md5Hash.ComputeHash(buffer); // B64(MD5(clientID:secret)): string tmp2 = String.Format("{0}:", Convert.ToBase64String(output)); byte[] tmp3 = Encoding.UTF8.GetBytes(tmp2); // convert input: ServerNonce from Base64 to a byte array. byte[] tmp4 = Convert.FromBase64String(ServerNonce); // MD5(B64(MD5(clientID:secret)):nonce) byte[] buffer2 = newbyte[tmp3.Length + tmp4.Length]; tmp3.CopyTo(buffer2, 0); tmp4.CopyTo(buffer2, tmp3.Length); output = md5Hash.ComputeHash(buffer2); // MD5(B64(MD5(clientID:secret)):nonce) hash = Convert.ToBase64String(output); return hash; }