A Big Integer Package for Use in Visual Basic Written in Visual C++

Introduction

This article is simple a 'How To' in creating a COM object in Visual C++ for use in COM-aware languages such as Visual Basic. In addition, the library that is created is a Large Integer package. The underlying cryptographic code is Wei Dia's Crypto++ (www.cryptopp.com).

Crypto++ has been NIST certified for those who are interested in authoring FIPS 140-2 conformant software. To enjoy the Certification, one must use the DLL version of the Crypto++ Library.

For those who are interested in other C++ Number Theoretic libraries, please see Peter Gutmann's Cryptlib (www.cs.auckland.ac.nz/~pgut001/cryptlib) or Victor Shoup's NTL (www.shoup.net/ntl).

Compiling and Integrating Crypto++ into the Microsoft Visual C++ Environment

Please see the related article, "Compiling and Integrating Crypto++ into the Microsoft Visual C++ Environment." This article is based upon basic assumptions presented in the previously mentioned article. It also addresses most problems encountered with projects from Command Line to MFC projects (Errors C1083, C1189, LINK2001, and LINK2005).

Using the ATL Wizard to Create the COM DLL

Open Visual C++ and select New ATL COM AppWizard Project.

Next, click 'OK'. At the final step, select a DLL, and allow merging of the Proxy/Stub code. At this point, the Wizard has created the framework of the COM object. If you want familiar Visual C++ favorites such as CString, check the 'Support MFC' box.

Select Project | Settings, C++ Tab. Under 'Settings For', Select 'All Configurations'.

Remove references to '_MBCS', and add 'UNICODE' and '_UNICODE'.

Under the 'C++ Language' Category, select 'Enable Exception Handling'.

Remove the _ATL_MIN_CRT Preprocessor Definition from the Release Builds.

Add the following to stdafx.h::

#ifdef _DEBUG
#  pragma comment( lib, "cryptlibd" )
#else
#  pragma comment( lib, "cryptlib" )
#endif

#pragma warning( push, 3)
#include "integer.h"
#include "nbtheory.h"
#include "algebra.h"
#include "osrng.h"
#pragma warning( pop )

#pragma warning( disable : 4661 )

#ifndef VT_TRUE
#    define VT_TRUE (VARIANT_BOOL)-1
#endif

#ifndef VT_FALSE
#    define VT_FALSE (VARIANT_BOOL) 0
#endif

const HRESULT E_CRYPTOPP   = MAKE_HRESULT( SEVERITY_ERROR,
                                           FACILITY_ITF, 0x200+00);
const HRESULT E_BIGINTEGER = MAKE_HRESULT( SEVERITY_ERROR,
                                           FACILITY_ITF, 0x200+01);

Add a New ATL Object to the project. This is the interface that the COM client will use.

Choose a Simple Object.

Name the object 'BigInteger'.

A Big Integer Package for Use in Visual Basic Written in Visual C++

The Code

The ATL project now has two separate entities: an interface (that the COM client will use), and a class file (that will hold various functions and a member variable). Methods and Properties will be added to the Interface (IBigInteger), and Functions and Variables will be added to the class file (CBigInteger).

The files of interest that will now be used the most are BigInteger.h, BigInteger.cpp, and tt>Integer.idl. The MIDL compiler will use Integer.idl to create the export table of the object (similar to a self-contained DEF file).

Add a private member variable to the CBigInteger class: Select the 'ClassView' tab in the Visual C++ editor, and then right-click on the CBigInteger and Select 'Add Member Variable'.

[add_member.gif]

Add the private m_Integer as shown below. If you are unable to add it as a CryptoPP::Integer, add it as an INT, and then edit the type in the BigInteger.h header file. Note that, when working with interfaces, you will not be able to access this member directly.

[integer_member.gif]

Next, add a Property to the interface. Right-click the IBigInteger interface and select 'Add Property'.

[add_property.gif]

The hidden property _Value will be used to access the underlying BigInteger. This is the same property that Visual Basic will call to get the tool tip for displaying the value of the BigInteger in the Visual Basic editor when hovering the mouse over a variable.

[add_property_dialog.gif]

Note the ID number (36 in the above example). If this property is not 0, edit the Integer.idl file so that it becomes ID 0. Simply sequentially renumber other IDs as required. The remaining Property and Method IDs are not of much significance.

//
// From Integer.idl
//
interface IBigInteger : IDispatch
   {
      [propget, id(0), helpstring("The decimal string representation
                                   of the big integer.")]
      HRESULT _Value([out, retval] BSTR *pVal);

      [propput, id(0), helpstring("The decimal string representation
                                   of the big integer.")]
      HRESULT _Value([in] BSTR newVal);

      [id(1), helpstring("The decimal string representation of the
                          big integer.")]
      HRESULT AsDecimal([out, retval] BSTR* pVal);

      ...
   };

A final note on the put/get property _Value: It is the default property of the object. This works extremely well for the BigInteger (and VB TextBoxes, for that matter). It is hidden in the Visual Basic Object Browser due to the leading underscore. Visual C++ will decorate this property to put__Value(...) and get__Value(...) in the CBigInteger class. The get__Value(...) returns a decimal string (BSTR) representation of the underlying BigInteger. The corresponding put__Value(...) accepts the decimal representation of a big integer, and sets the m_Integer member to that value.

The effect of the previous is that a programmer can perform the following:

Dim i As BigInteger

Set i = New BigInteger

' VB will set the _Value property
'   VC++ will have the put__Value( BSTR ) function invoked
i = "123456789123456789123456789123456789"

' VB will get the _Value property
'   VC++ will have the get__Value( ) function invoked
Debug.Print i

Set i = Nothing

Before _Value is coded, a helper function is needed to create the string. Add it as a protected member function of CBigInteger. Code it as follows. In keeping with the COM model, it will return an HRESULT. pbszValue will receive the string, and pInteger is the CryproPP::Integer that will be transformed into a human-readable digit string. Note also the call to the helper function ReverseString(...).

HRESULT CBigInteger::ToString( BSTR* pbszValue, UINT radix,
                               CryptoPP::Integer* pInteger)
{
   HRESULT hr = E_FAIL;
   CryptoPP::Integer temp1, temp2;

   OLECHAR* s;       // String of length 'size'
   UINT size = 0;    // OLE char[] size for building representation
   UINT i = 0;       // Looping control

   const OLECHAR vec[] = OLESTR("0123456789ABCDEF");

   if( 1 > radix || 16 < radix ) {

      hr = E_INVALIDARG;

      goto FINISHED;
   }

   if( NULL == pInteger ) {

      temp1 = m_Integer;
   } else  {

      temp1 = *pInteger;
   }

   // if pVal = NULL, VB is sending in what it considers an
   // empty ("") string
   // if *pVal is not NULL, it must be freed
   if( NULL != pbszValue && NULL != *pbszValue ) {

      ::SysFreeString( *pbszValue );
      *pbszValue = NULL;
   }

   /////////////////////////////////////////////////////////////
   // size
   //   Wei Dai's code:
   //     CryptoPP::BitCount() / ( CryptoPP::BitPrecision(base)-1)
   //                              + 1)
   //   We add 1 for the terminating '\0'
   size = ( temp1.BitCount() / ( CryptoPP::BitPrecision(radix)-1)
   //                            + 1) + 1;

   /////////////////////////////////////////////////////////////
   // Add 1 for the '-' sign
   if( temp1.IsNegative() ) { size++; }

   s = new OLECHAR[ size ];

   if( NULL == s ) {

      hr = E_OUTOFMEMORY;

      goto FINISHED;
   }

   ZeroMemory( s, size * sizeof(OLECHAR) );

   if ( temp1.IsNegative() ) {

      s[ i++ ] = OLECHAR('-');
      temp1.Negate();
   }

   if ( !(temp1) ) {

      s[ i++ ] = OLECHAR('0');

   } else {

      // This generates the string in reverse order
      while (!!temp1) {

         CryptoPP::word digit;
         CryptoPP::Integer::Divide(digit, temp2, temp1, radix);
         s[i++]=vec[digit];
         temp1=temp2;
      }

      // And reverse it
      ( s[0] == OLECHAR('-') ) ? ReverseString( &s[1], i-1) :
                                 ReverseString( s, i );

   }

   *pbszValue = ::SysAllocString( s );

   hr = S_OK;

FINISHED:

   if( NULL != s ) { delete[] s; }

   return hr;
}

A Big Integer Package for Use in Visual Basic Written in Visual C++

In the definition of _Value (get__Value in BigInteger.cpp), add the following source code.

STDMETHODIMP CBigInteger::get__Value(BSTR *pVal)
{
HRESULT hr = E_FAIL;

   try {

      // if pVal = NULL, VB is sending in what it considers an
      // empty ("") string
      // if *pVal is not NULL, it must be freed
      if( NULL != pVal && NULL != *pVal ) {

         ::SysFreeString( *pVal );
         *pVal = NULL;
      }

   } catch( ... ) { /* Ignore */ }

   try {

        hr = ToString( pVal, 10 );

   } catch( ... ) {

      Error( OLESTR( "Error extracting the string." ) );

      hr = E_FAIL;
   }

   if( NULL == *pVal ) { 

      Error( OLESTR( "Memory allocation error extracting the
                      string." ) ); 

      hr = E_OUTOFMEMORY;
   }

   return hr;
}

Add Methods to the Object as required.

[add_method.gif]

For example, Modulo(...) would be coded as follows. Note the [out, retval] attributes added to the method from above. out informs the MIDL compiler that the interface will be written to, and the retval attribute informs the MIDL compiler this is the return value of the function. A out value type must be of the type IBigInteger**—an in value type will be of the type IBigInteger*.

STDMETHODIMP CBigInteger::Modulo(IBigInteger* m,
                                 IBigInteger** ppResult)
{
   HRESULT hr = E_FAIL;
   BSTR    bszValue = NULL;
   CryptoPP::Integer _i1, _i2;

   try {

      if( NULL == m || NULL == ppResult ) { goto FINISHED; }



      if( NULL == *ppResult ) {

         hr = CreateBigInteger( ppResult );

         if( FAILED( hr ) ) { goto FINISHED; }
      }



      hr = m->get__Value( &bszValue );

      if( FAILED( hr ) ) { goto FINISHED; }

      _i1 = CryptoPP::Integer( bszValue );




      _i2 = m_Integer.Modulo( _i1 );



      hr = ToString( &bszValue, 10, &_i2 );

      if( FAILED( hr ) ) { goto FINISHED; }

      (*ppResult)->put__Value( bszValue );

      hr = S_OK;
   }

    catch ( CryptoPP::Exception& e ) {

      Error( e.what() );

      hr = E_CRYPTOPP;
   }

   catch( ... ) {

      Error( OLESTR( "Error performing Modulo." ) );
      hr = E_FAIL;
   }

FINISHED:

   if( NULL != bszValue ) { SysFreeString( bszValue ); }

   return hr;
}

The above code is typical. Note that all functions catch throws and simply return a COM error. Never let a throw go uncaught into the COM client. The BigInteger Library will catch all errors, and return the error as an HRESULT which will be one of the following:

  • E_FAIL or the original COM error
  • E_CRYPTOPP if the throw originated in the Crypto++ Library
  • E_BIGINTEGER if the error originated in CBigInteger

See "Strategies for Handling Errors in COM" for a discussion of COM errors.

Computation is performed as follows (notice that the object itself—m_Integer—is generally not modified):

   //
   // from Modulo(...)
   //
   _i2 = m_Integer.Modulo( _i1 );

or

   //
   // from ModMultiply(...)
   //
   _i3 = CryptoPP::a_times_b_mod_c( m_Integer, _i1, _i2 );

The Value then is written back as a BSTR using put__Value(...). Never attempt to access the m_Integer member through the interface (for example, by attempting to return a pointer to m_Integer through a method). Imagine a distributed situation where the class is instantiated on a separate machine. The CBigInteger will simply receive a bad address.

   hr = ToString( &bszValue, 10, &_i2 );

   if( FAILED( hr ) ) { goto FINISHED; }

   (*ppResult)->put__Value( bszValue );

Finally, there is a call to CreateBigInteger(...):

   hr = CreateBigInteger( ppResult );

CreateBigInteger(...) handles the COM object creation dirty work (this is not the best method for remoting object creation):

HRESULT CBigInteger::CreateBigInteger(IBigInteger ** ppBigInteger)
{
   HRESULT hr = E_FAIL;
   IClassFactory* pClassFactory = NULL;

   try {

      assert( NULL == *ppBigInteger );

      hr = CoGetClassObject( CLSID_BigInteger, CLSCTX_ALL, 0,
                             IID_IClassFactory,
                             reinterpret_cast<VOID**>
                             ( &pClassFactory ) );

      if( FAILED( hr ) ) { goto FINISHED; }

      hr = pClassFactory->CreateInstance( NULL, IID_IBigInteger,
                                          reinterpret_cast<VOID**>
                                          ( ppBigInteger ) );

      (*ppBigInteger)->AddRef();

      pClassFactory->Release();
   }

   catch( ... ) { ; }

FINISHED:

    return hr;
}

A Big Integer Package for Use in Visual Basic Written in Visual C++

Most wrappings are straightforward from C++ function overloading. However, there are a few where one must use functions from the Crypto++ nbtheory.h and algebra.h. For example, multiplicative inverse and exponentiation. The functions are provided so the reader does not have to grep the source files with a number theoretic background:

// Multiplicative Inverse
//
_i3 = CryptoPP::EuclideanMultiplicativeInverse( _i1, _i2 );

// Exponentiation
//
_i3 = CryptoPP::EuclideanDomainOf<CryptoPP::Integer>
   ().Exponentiate( _i1, _i2 );

Be advised it is very easy to run out of memory when performing Exponentiation, which is not over a finite field.

The DLL also has a custom type specified in the Integer.idl file—a JacobiResult for determining Jacobi symbols. Use GUIDGen.exe for creating the uuid.

// From Integer.idl
//
typedef [
   uuid(AEFE64AC-3B6F-45E6-8F32-B726FF9876E8),
   helpstring("Jacobi Results"),
]

enum JacobiResult {
   [
      helpstring("This object is not a Quadratic Residue in
                  BigInteger n; and is not equal to 0."),
   ] JacobiOther = -1,

   [
      helpstring("This object modulo BigInteger n equals 0."),
   ] JacobiZero = 0,

   [
      helpstring("This object is a Quadratic Residue in BigInteger
                  n."),
   ] JacobiResidue = 1,

} JacobiResult;

As with C++, once the type is declared it can be used in any Method (IBigInteger) or Function (CBigInteger):

STDMETHODIMP CBigInteger::JacobiSymbol(IBigInteger *n,
                                       JacobiResult *pJacobi)
{

   HRESULT hr = S_OK;
   BSTR    bszValue = NULL;
   CryptoPP::Integer _i1, _i2;

   try {

      if( NULL == n || NULL == pJacobi ) { goto FINISHED; }

      _i1 = m_Integer;

      ...

      switch ( CryptoPP::Jacobi( _i1, _i2 ) ) {

         case -1:
            *pJacobi = JacobiOther;
            break;

         case 0:
            *pJacobi = JacobiZero;
            break;

         case 1:
            *pJacobi = JacobiResidue;
            break;

         default:
            Error( OLESTR("Error calculating the Jacobi symbol.") );

            hr = E_FAIL;
        }
   }

    catch ( CryptoPP::Exception& e ) {

      Error( e.what() );

      hr = E_CRYPTOPP;
   }

   ...

   return hr;
}

Using the Library in Visual Basic

Compile the library, and then press F5 to run the project. When prompted, select Visual Basic as the executable to run. Note that breakpoints in the Visual C++ editor are honored.

[debug_exe.gif]

Create a new Visual Basic Project. Add a Reference to the DLL. Select Project | References. Browse to the DLL as required. Note that the DLL should be on the local machine (and not a mapped drive).

[vb_reference.gif]

If the programmer would like to change the friendly display name ('Integer 1.0 Type library'), simply edit the integer.idl file at the library keyword:

[tlb_version.gif]

Now that the Library is referenced, press F2 in the Visual Basic editor to open the Object Browser. Select BIG_INTEGER rather than <All Libraries>.

[object_browser.gif]

And finally, a small driver program. Notice the following occurs in the Visual Basic environment:

  • Dim the variable as a BigInteger
  • Set the variable to a new BigInteger before use
  • Set the variable to Nothing after use
Private Sub Form_Load()

Dim i As BigInteger
Dim j As BigInteger
Dim k As BigInteger

Set i = New BigInteger
Set j = New BigInteger
Set k = New BigInteger

i.GenerateMaurerPrime (64)
Debug.Print i
j.GenerateMihailescuPrime (96)
Debug.Print j

k = i.ModInverse(j)
Debug.Print k

Set i = Nothing
Set j = Nothing
Set k = Nothing

[generate_integer.gif]

Library Functionality

The following tables describes the methods made available by the BigInteger Library.

r = i.Add( a ) r = i + a Addition
r = i.Subtract( a ) r = i - a Subtraction
 
r = i.Multiply( b ) r = i * b Multiplication
 
r = i.Divide( b ) r = i / b Remainder is discarded
r = i.Remainder( b ) r = remainder of i / b Quotient is discarded
 
r = i.SquareRoot( ) r = FLOOR(i1/2)  Square Root
 
r = i.Power( e ) r = ie Exponentiation
 
i.Decrement( ) i = i - 1 Changes the object
i.Double( ) i = i * 2 Changes the object
i.Halve( ) i = i / 2 Changes the object
i.Increment( ) i = i + 1 Changes the object
i.Square( ) i = i2 Changes the object
 
r = i.LeftShift( n ) r = i << n Left Shift n bits (n is not a BigInteger)
r = i.RightShift( n ) r = i >> n Right Shift n bits (n is not a BigInteger)
 
r = i.Modulo( m ) r = i mod m Modulo
r = i.ModInverse( m ) r = i-1 mod m Modular Inverse
r = i.ModMultiply( b, m ) r = (i * b) mod m Modular Multiplication
r = i.ModPower( e, m ) r = ie mod m Modular Exponentiation
 
r = i.GCD( b ) r = GCD( i, b ) Greatest Common Denominator
r = i.LCM( b ) r = LCM( i, b ) Least Common Multiple
 
r = i.JacobiSymbol( b ) r = J( i, b ) Calculates the Jacobi Symbol
 
r.ChineseRemainder( xmodp, p, xmodq, q )   r is set to the solution to the Chinese Remainder Theorem

References and Further Reading

  • Essential COM by Don Box, ISBN 0-201-63446-5
  • Advanced Visual Basic 6: Power Techniques for Everyday Programs by Matthew Curland, ISBN 0-201-70712-8
  • The Art of Computer Programming, Seminumerical Algorithms by Donald Knuth, ISBN 0-201-89684-2
  • Handbook of Applied Cryptography by Menezes, van Oorchot, and Vanstone, ISBN 0-8493-8523-7
  • Applied Cryptography by Bruce Schneier, ISBN 0-471-12845-7

History

  • 11/14/2006: Updated Crypto++ and VC++ Integration
  • 10/1/2005: Added FullDivide(divisor, quotient, remainder) Method
  • 9/30/2005: Added Generate Integer sample Screen Shot
  • 9/30/2005: Added samples to VB Driver
  • 9/28/2005: Fixed Method Table Formatting
  • 9/28/2005: Added Descriptions for Download Files
  • 9/18/2005: Initial Article Release


About the Author

Jeffrey Walton

In the past, I have worked as an IT consultant for County Government (Anne Arundel County), the Nuclear Energy Institute, the Treasury Department, and Social Security Administration as a Network Engineer and System Administrator. Primary Administration experience includes Microsoft Windows and Novell Netware, with additional exposure and familiarity with Mac and Linux OSes. Previous to the US government, I was a programmer for a small business using Microsoft Visual Languages (Basic 5.0, 6.0, and C++ 5.0, 6.0) and Scripting Languages. An undergraduate degree (BS in Computer Science) was obtained from University of Maryland, Baltimore County. Graduate work includes a Masters of Science (Computer Science) from Johns Hopkins University (expected before 2009). Training and Certifications include Microsoft, Checkpoint, and Cisco.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • A modern mobile IT strategy is no longer an option, it is an absolute business necessity. Today's most productive employees are not tied to a desk, an office, or a location. They are mobile. And your company's IT strategy has to be ready to support them with easy, reliable, 24/7 access to the business information they need, from anywhere in the world, across a broad range of communication devices. Here's how some of the nation's most progressive corporations are meeting the many needs of their mobile workers …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds