Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Using JNI to read Window-My in Java

4.00/5 (1 vote)
19 Mar 2013CPOL2 min read 11.7K   233  
Using JNI to read Window-My in Java.

Introduction

In this article we shall see how Java can access an MS certificate in Personal Certificates.

Background

Back to my Java project, I want to use a MS certificate to validate clients before sending a request to my web server to get back a runtime jar file. I try to open "Window-My" to read a Personal Certificate in Java but no luck at all. After searching on Google a while I come to a conclusion to use JNI in Java to call a VC++ function. In turn the VC++ function will call a C# module to access the Personal Certificate.

Using the code

The attached code is built using C# 2005, VC++ 2005, and Java 6.0. It has:

  • Java Application
  • C# class (code module)
  • VC++ library (library.dll)

Let's break it down

First we create a Java class named LoadCert.java and compile to LoadCert.class.

Java
public class LoadCert {    
    public native String encryptedData();
    static {
        System.loadLibrary("LoadCert");
    }
    public static void main (String[] args) {
        String test = new LoadCert().encryptedData(); 
        System.out.print(test);       
    }
}

Using javah -jni LoadCert to generate LoadCert.h for VC++ library uses later on.

C++
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class LoadCert */

#ifndef _Included_LoadCert
#define _Included_LoadCert
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Package: 
 * Class:     LoadCert
 * Method:    encryptedData
 * Signature: ()Ljava/lang/String;
 * JNIEXPORT jstring JNICALL Java_package_className_methodName
 */
JNIEXPORT jstring JNICALL Java_LoadCert_encryptedData
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

Next we create a C# module to access the MS certificate for the VC++ library call.

Let's create a C# class called CSharpCert.cs.

C#
using System;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public class CSharpCert
{
    public CSharpCert() { }
    public string encryptedData() 
    {
        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection cert = 
          store.Certificates.Find(X509FindType.FindBySubjectName, System.Net.Dns.GetHostName(), false);
        if (cert.Count == 0) return string.Empty;
        DateTime expired = Convert.ToDateTime(
          cert[0].GetExpirationDateString(), new System.Globalization.CultureInfo("en-GB"));
        if (expired.CompareTo(DateTime.Now) < 1) return string.Empty;
        RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert[0].PublicKey.Key;
        byte[] bytes = Encoding.UTF8.GetBytes(System.Net.Dns.GetHostName());
        return ToStringByte(rsa.Encrypt(bytes, false)); 
    }
    private string ToStringByte(byte[] bytes)
    {
        string ret = "";
        for (int i = 0; i < bytes.Length; i++)
            ret += bytes[i].ToString("X2");
        return ret;
    }
}

Then create a C# module named CSharpCert.netmodule.

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc /target:module 
  /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll CSharpCert.cs

Last part we create VC++ 2005 project

Create two folders named Java and MCPP under the LoadCert project name. Add LoadCert.h into the Java folder. Create a header for this project and add it into the MCPP folder.

C++
#include <string.h>
#using <mscorlib.dll>
#using "CSharpCert.netmodule"

using namespace System;
using namespace System::Runtime::InteropServices;

// This code wraps the C# class using Managed C++
public __gc class LoadCertC
{
public:
    CSharpCert __gc *t; // Provide .NET interop and garbage collecting to the pointer.

    LoadCertC() {
        t = new CSharpCert(); // Assign the reference a new instance of the constructor.
    }

    char* callEncryptedData() {         
        System::String * str = t->encryptedData();
        char* str2 = (char*)(void*)Marshal::StringToHGlobalAnsi(str);
        char *copy = new char[strlen(str2)+1];
        strcpy(copy,str2);
        Marshal::FreeHGlobal(str2);
        return copy;
    }
};

Add LoadCert.cpp into the source files.

C++
#include <jni.h>

// This is the java header created using the javah -jni command.
#include "Java\LoadCert.h"

// This is the Managed C++ header that contains the call to the C#
#include "MCPP\LoadCert.h"

// This is the JNI call to the Managed C++ Class
// NOTE: When the java header was created, the package name was not included
//       in the JNI call. This naming convention was corrected by adding the 
//       Java_<package name>_<class name>_<method name>
JNIEXPORT jstring JNICALL Java_LoadCert_encryptedData(JNIEnv *jn, jobject jobj) {

    // Instantiate the MC++ class.
    LoadCertC* t = new LoadCertC();

    // The actual call is made. 
    char* str2 = t->callEncryptedData();
    return (jstring) jn->NewStringUTF(str2);
}

The last thing is set up VC++ to point to jni.h and CSharpCert.netmodule. Right click on Project --> Properties, expand C/C++, click on Additional Include Directories to JDK\Include and JDK\Include\Win32 to point to jni.h. Click on resolve #using References to CSharpCert.netmodule.

Click on Command line and add /clr:oldSyntax, expand linker, click on Command line and add /NOENTRY /NODEFAULTLIB:nochkclr.obj /NODEFAULTLIB:MSVCRTD /NODEFAULTLIB:LIBCMTD.

Compile to LoadCert.dll.

Copy CSharpCert.netmodule and the libray DLL to the folder that contains LoadCert.class then run java LoadCert.

Points of Interest

What we want to know in this article is understand why JNI is necessary and useful. There are various examples on the internet about JNI. But here we have only touched the very basics of JNI in this article and why we need JNI.

History

  • 19 March 2013: First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)