The SNTP Frame

Looking at what is in the SNTP Frame

There are two SNTP versions in circulation: version 3 and version 4 that includes an option for authorisation. Both version use the same 48 byte beginning, with only the version number being different. In both cases if only 48 bytes are sent the reply is the same. However version 4 allows for authorisation to verify the data interchange for security reasons, this adds a further 28 bytes to frame.

The SNTP Frame

These are the first 48 bytes common to both version3 and version 4. If a version 4 frame sends only 48 bytes then authorisation is not assumed.

Byte 0 Byte 1 Byte 2 Byte 3
FLAG Stratum Poll Precision
Root Delay
Root Dispersion
Reference ID
Reference Timestamp (64)
Origin Timestamp (64)
Receive Timestamp (64)
Transmit Timestamp (64)

FLAG is further divided into 3 values over 8 bits

Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7
Leap Version Mode

In the case of Version 4 there are additional bytes added to the frame3. Two sets of variable length extension, then the bytes that are used for authorisation.

Byte 0 Byte 1 Byte 2 Byte 3
Extension Field 1 (variable, 128 bit minimum)
Extension Field 2 (variable, 128 bit minimum)
Key ID
Message Digest (128)

It is alright seeing the frame format but what do all the fields mean. Here only use as a client is assumed, for the purpose of inserting the information. For detailed information see the latest NTP specification.

Item Purpose
Leap The leap year indicator. Returned by server, sent as 0
Version The version number. Sent by client, returned by server, sent as 3 or 4
Mode The mode. Sent by client, returned by server, sent 3 for client mode
Stratum The stratum level of the server. Client sends 16 for unsynchronised
Poll Maximum time between messages as log2 seconds. Client sent default 10
Precision Precision of the client clock log2 seconds. Client sent default -4
Root Delay Round trip delay of reference clock (NTP short format). Client sends 0
Root Disperion Time dispersion of reference clock (NTP short format). Client sends 0
Reference Timestamp Time when client clock was last corrected. Client sends last arrival timestamp
Origen Timestamp Time when client emits the time request.
Receive Timestamp Time when client request is received by the NTP server.
Transmit Timestamp Time when NTP server replies to the request.
Key ID Used by the client and server to designate a secret 128-bit MD5 key
Message Digest 128-bit MD5 keyed hash computed over the key over the NTP packet header + extensions fields
Extension Fields These are optional 16 byte free to use extensions. Usage must be padded to 16 byte minimum.

Expanding this.

The timestamps are the reason. Timestamps are 32 bit UTC definitions of time. The upper 16 bits are the time in UTC seconds and the lower 16 bits the UTC fraction of seconds. This gives an accuracy of opproximately 233 pSec!!!

UTC is defined as the Epoch in seconds from 1st January, midnight of the year 1900., NOT to be confused with UNIX Epoch that is the number of seconds from 1st January, midnight of the year 1970.

As a bonus, here are some routines for conversion to and from NTP timestamps.

Conversion of a timestamp to a DateTime class:

        public static DateTime TimeStampToDateTime(UInt64 timestamp)
            DateTime sntp_timemark_begin = new DateTime(1900, 1, 1, 0, 0, 0);
            UInt32 t_sec = (UInt32)(timestamp >> 32);
            UInt32 t_frac = (UInt32)((timestamp & 0x00000000FFFFFFFF) / 429);
            TimeSpan elapsedSeconds = TimeSpan.FromSeconds(t_sec);
            TimeSpan elapsedFraction = TimeSpan.FromTicks(t_frac);
            TimeSpan elapsedTime = elapsedSeconds.Add(elapsedFraction);
            DateTime time = sntp_timemark_begin + elapsedTime;
            return time;

Conversion of a DateTime class into the two parts of a timestamp:

        public static void SNTP_TimeMark(ref UInt32 t_secs, ref UInt32 t_frac, DateTime t_initial)
            //  Places a SNTP timemark given a DateTime object
            //  The SNTP timemark origin = 0hrs 1st jan 1900
            DateTime sntp_timemark_begin = new DateTime(1900, 1, 1, 0, 0, 0);
            Int64 elapsedTicks = t_initial.Ticks - sntp_timemark_begin.Ticks;
            TimeSpan elapsedSpan = TimeSpan.FromTicks(elapsedTicks);
            t_secs = (UInt32)elapsedSpan.TotalSeconds;
            TimeSpan elapsedFraction = elapsedSpan.Subtract(TimeSpan.FromSeconds(t_secs));
            // The Ticks are at 100nSec. the SNTP timemark ios 233pSec so x factor = 100e-9 / 233e-12 = 429
            t_frac = (UInt32)(elapsedFraction.Ticks * 429);

Conversion of a NTP Epoch into the UNIX Epoch:

        public static UInt32 UTCToEpoch(UInt64 timestamp)
            DateTime time_in = TimeStampToDateTime(timestamp);
            DateTime epoch_begin = new DateTime(1970, 1, 1, 0, 0, 0);
            TimeSpan epoch_time = time_in - epoch_begin;
                Double epoch_Sec = epoch_time.TotalSeconds;
                UInt32 Sec = Convert.ToUInt32(epoch_Sec);
                return Sec;
            catch {  return 0; }

Authentication complicates things!.

Authentication is a big feature of version 4 NTP ( In NTPv3 it was limited). If the extension fields are used it is obligatory.

Essentially an agreement is made between the client and the reference time server to exchange verifiable data. To this end a private key is shared between the two parties. each generates a keyed MD5 hash of the data in the frame from byte 0 to the end of the extension fields, inclusive. This 128 bit hash is placed in the Message Digest space. Since several possible keys will be used by the NTP servers, the Key ID form a list of fields is used to identify to either end the secret key to be used to generate the hash. If the hash generated from the data received does not agree with the hash sent we know that the frame has been compromised.

The previous is call symmetrical authorisation since it involve the transfer of a private key by secure means and works for both ways of transmission. The alternative is to use SHA encryption which is much more secure but involves installing the SHA256 library. The private key is only kept at one end and a public key given out.

Here we come to some obvious uses for the extension fields: error correction data, asymettrical transmission timestamp data, rolling hash keys.