white spy  PPP Logo

GRC's Open, Ultra-High Security,
One Time Password System
  black spy


DLL Code Implementation

To encourage and enable anyone who would be interested in implementing this PPP system for their own application or web service, we have published the complete Windows version of the PPP CryptoSystem in a single 15 Kbyte standalone, high-performance (100% assembly language) Windows dynamic link library (PPP.DLL).

We also include an accompanying 12 Kbyte Windows command-line utility (PPP.EXE) which uses the PPP.DLL. The executable can be used as a "shell command" by any other language environment. And, finally, as an aid to generating web page displays of PPP passcards, we provide the various HTML resources used on this site for the display of the PPP passcards:


     http://www.GRC.com/files/ppp.zip     


This Windows PPP.DLL may be readily called from any language and operating system platform that supports loading and calling into Windows DLLs. And, similarly, the PPP.EXE can be invoked on any platform that can run Windows command-line executable programs.
The complete PPP CryptoSystem in a 15 Kbyte DLL
Please see your chosen language's documentation for information on calling Windows DLL functions. As is thoroughly documented below, the PPP.DLL contains high speed assembly language implementations of the two cryptographic functions required by the PPP system, a 256-bit secure hash algorithm (SHA256) and a 256-bit keyed, 128-bit/block Rijndael/AES cipher. These are used by the main DLL library function to generate any sequence of PPP passcodes given a 256-bit "sequence key", the 0-based ordinal of the first passcode desired, and the number of passcodes requested.

The PPP.DLL also includes a collection of utility functions, such as a 256-bit cryptographic random number generator for easily creating unique PPP "sequence keys", as well as functions for performing math on large 128-bit values and for converting binary passcodes into their 4-character ASCII equivalent.

By using the PPP.DLL to perform the "heavy lifting" crypto operations and the various bit-manipulation operations, fully PPP-compliant highly secure one-time password authentication systems can be created with a minimum of coding and zero guesswork.

The PPP.DLL Application Programming Interface (API)
The PPP.DLL library is a standard Windows-style DLL compatible with 32-bit versions of Microsoft languages. It follows 'C' naming conventions and PASCAL calling conventions. As such, procedure parameters are pushed onto the stack in right-to-left order, and the called procedure is responsible for cleaning up the stack after the call to remove the caller's parameters.

Additionally . . .
  • Integer parameters are 32-bits unsigned.
  • Integer return values are 32-bits signed.
  • Pointers are 32-bit flat addressing.
  • Strings are null-terminated 8-bit ASCII.
  • Byte-ordering is Intel-style little endian.
    (Least significant bits/bytes always come first.)
The PPP.DLL provides the following functions:

RetrievePasscodes
PasscodeCharBuffer:Pointer to buffer that receives retrieved passcode characters. The buffer must be at least (PasscodeCount * Passcode Length) bytes long. Successive passcode characters are stored one character per byte.
FirstPasscodeNumber:Pointer to 128-bit (16 byte) buffer specifying the 0-based ordinal of the first passcode to retrieve. This pointer can be NULL to request retrieval from the first (0th) passcode.
PasscodeCount:Integer specifying the number of passcodes to retrieve.
SequenceKey:Pointer to a 256-bit (32-byte) buffer containing the PPP "Sequence Key" of the passcodes retrieved.
CharacterSet:Pointer to a zero-terminated string containing the target PPP character set. It will be sorted into ascending ASCII order before use.
PasscodeLength:Integer specifying the number of characters per passcode.

No return value.


"RetrievePasscodes" is the PPP.DLL's primary function. It fills a user-provided buffer with any number of requested passcodes, each of passcode length, occupying one byte per passcode character and with no inter-passcode padding or spacing. The passcodes are generated using the algorithm described on the "Algorithm" page. This function would typically be used to generate the data for a PPP passcard and to check a user-provided passcode. For example, to generate passcard 'N', given 70 passcodes per card, the 0-based first passcard number requested would be 70×(N-1).


GenerateRandomSequenceKey
SequenceKeyBuffer:Pointer to a 256-bit (32-byte) buffer which will receive a "Sequence Key" compatible with the "RetrievePasscodes" function.

No return value.


"GenerateRandomSequenceKey" fills the user-provided buffer with a highly random, unpredictable and unrepeatable 256-bit value. The value is generated by using the SHA256 cryptographic hash on a number of machine specific and extremely volatile values, including the current high-resolution time, the number of processor clock cycles since last reset, and a GUID that incorporates the machine's unique Ethernet adapter MAC address. The values returned by this function would typically be stored and associated with individual user accounts then provided to the "RetrievePasscodes" procedure as needed.


ConvertAsciiTo128BitDecimal
BinaryBuffer:Pointer to a 128-bit (16-byte) buffer which will receive the result of an ASCII to decimal conversion
AsciiString:Pointer to a null-terminated ASCII string containing only ASCII digits 0-9 and possibly commas.

Returns:1:Successful conversion with non-zero result.
0:Zero result.
-1:Invalid characters in string.
-2:Overflow - binary conversion would have required more than 128-bits.


"ConvertAsciiTo128BitDecimal" performs an ASCII to decimal conversion upon a null-terminated input string which may contain commas (which will be ignored). The 32-bit (signed) return value indicates the outcome of the operation.


AddDwordTo128bits
ValueBuffer:Pointer to a 128-bit (16-byte) buffer to which the 32-bit addend will be added.
Addend:A 32-bit value (addend) which will be added to the 128-bit "ValueBuffer."

Returns:0:Success.
-1:Result overflowed the 128-bit ValueBuffer.


"AddDwordTo128bits" performs simple math on a 128-bit value. It adds the 32-bit value provided in the "Addend" to the current value contained in the 128-bit (16-byte) buffer pointed to by "ValueBuffer". If the addition does not cause the value in the buffer to overflow, the function returns a value of '0' to indicate success. If the value overflows, '-1' is returned in the 32-bit result (all 1's). Note that in this case, the 32-bit addend value will have been added to the ValueBuffer, allowing it to "wrap around", and the function's non-zero result can be taken as a "carry" out of the ValueBuffer's most significant bit.


SubtractDwordFrom128bits
ValueBuffer:Pointer to a 128-bit (16-byte) buffer from which the 32-bit subtrahend will be subtracted.
Subtrahend:A 32-bit value (subtrahend) which will be subtracted from the 128-bit "ValueBuffer."

Returns:0:Success.
-1:Result underflowed the 128-bit ValueBuffer.


"SubtractDwordFrom128bits" performs simple math on a 128-bit value. It subtracts the 32-bit value provided in the "Subtrahend" from the current value contained in the 128-bit (16-byte) buffer pointed to by "ValueBuffer". If the subtraction does not cause the value in the buffer to underflow, the function returns a value of '0' to indicate success. If the value underflows, '-1' is returned in the 32-bit result (all 1's). Note that in this case, the 32-bit subtrahend value will have been subtracted from the ValueBuffer, allowing it to "wrap around", and the function's non-zero result can be taken as a "borrow" from the ValueBuffer's most significant bit.


Mult128bitsByDword
ValueBuffer:Pointer to a 128-bit (16-byte) buffer which will be multiplied by the value in the 32-bit multiplier.
Multiplier:A 32-bit value (multiplier) which will be multiplied by the value in the 128-bit "ValueBuffer."

Returns:0:Success.
-1:Result overflowed the 128-bit ValueBuffer.


"Mult128bitsByDword" performs simple math on a 128-bit value. It multiplies the 32-bit value provided in the "Multiplier" by the current value contained in the 128-bit (16-byte) buffer pointed to by "ValueBuffer". If the multiplication does not cause the value in the buffer to overflow, the function returns a value of '0' to indicate success. If the value overflows, '-1' is returned in the 32-bit result (all 1's). Note that in this case, the 32-bit multiplier value will have been multiplied by the ValueBuffer, and the ValueBuffer will contain the least significant 128-bits of the result.


Divide128bitsByDword
ValueBuffer:Pointer to a 128-bit dividend (16-byte) buffer which will be divided by the value in the 32-bit divisor.
Divisor:A 32-bit value (divisor) by which the 128-bit dividend will be divided.

Returns::32-bit remainder from division.


"Divide128bitsByDword" performs simple math on a 128-bit value. It divides the 128-bit buffer pointed to by "ValueBuffer" by the 32-bit value provided in the "Divisor". The remainder of the division operation returned by the function.
The PPP Command-Line Utility
The PPP Utility page describes the many functions provided by the PPP command-line utitilty.


Perfect Paper Password Pages:

Jump to top of page
Gibson Research Corporation is owned and operated by Steve Gibson.  The contents
of this page are Copyright (c) 2010 Gibson Research Corporation. SpinRite, ShieldsUP,
NanoProbe, and any other indicated trademarks are registered trademarks of Gibson
Research Corporation, Laguna Hills, CA, USA. GRC's web and customer privacy policy.
Jump to top of page

Last Edit: Feb 11, 2008 at 09:26 (762.51 days ago)Viewed 9 times per day