2013-04-05 7 views
4

SunMSCAPI 공급자에 서명하고 싶습니다. 공개 키 및 서명은 MS Crypto API를 사용하여 가져와야하기 때문에디지털 서명 SunMSCAPI 공급자 및 MS 암호화 API

일반적으로 SHA1withRSA으로 서명을 생성하면 빅 엔디안에서 리틀 엔디안 (바이트 순서) 변환으로 끝납니다. Java 응용 프로그램에서

//generate keystore with java keytool 
$Keytool -genkey -alias tsign -keystore c:\test\tsignjks.p12 - keyalg rsa -storetype pkcs12 

: 나는 SunMSCAPI 내 문제를 해결할 수 있습니다,하지만 난 MS 암호화 API를 사용하여 공개 키를 가져올 때 나도 몰라 있다고 생각

//for signing and getting keystore, assuming windows certificate is installed 
..ks = KeyStore.getInstance("Windows-MY","SunMSCAPI"); 
PrivateKey priv = ks.getKey("tsign",password); 
Signature rsa = Signature.getInstance("SHA1withRSA","SunMSCAPI"); 
rsa.initSign(priv); 
.. 
rsa.update(buffer, 0, len); 
.. 
byte[] realSig = rsa.sign(); 

//for writing public key for ms crypto api or exporting it from windows certificate store 
Certificate cert = ks.getCertificate("tsign"); 
byte[] encodedCert = cert.getEncoded(); 
FileOutputStream certfos = new FileOutputStream("tsigncer.cer"); 
certfos.write(encodedCert); 

//for writing signatures for ms crypto api 
FileOutputStream sigfos = new FileOutputStream(targetPath + "/" 
       + signatureName); 
sigfos.write(realSig); 

은, 그것은 첫 번째 단계에서에서 가져올 수 없다 (내가 빅 엔디안을 리틀 엔디안 바이트 순서로 변경하지 않는 한) 아래는 암호 API 용 코드입니다.

LPCSTR file = "tsigncer.cer"; 
//LPCSTR file = "omsign.p12"; 
BOOL crypt_res = FALSE; 

HCRYPTPROV crypt_prov_hndl = NULL; 
crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_RSA_FULL, 0/*CRYPT_NEWKEYSET*/); 
//crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT/*CRYPT_NEWKEYSET*/); 

    if (!crypt_res) { 
     HRESULT decode_hr = __HRESULT_FROM_WIN32(GetLastError()); 
     return decode_hr; 
    } 

    // Load key file 
    HANDLE fileHandle = CreateFile(file, // name of the write 
         GENERIC_READ,   // open for writing 
         0,      // do not share 
         NULL,     // default security 
         OPEN_EXISTING,    // create new file only 
         FILE_ATTRIBUTE_NORMAL, // normal file 
         NULL);     // no attr. template 

    if (fileHandle == INVALID_HANDLE_VALUE) 
    { 
     DWORD d = GetLastError(); 
     return -1; 
    } 

    BYTE buffer[2056]; 
    DWORD fileSize = 0; 
    DWORD fileSizeResult = GetFileSize(fileHandle, &fileSize); 

    DWORD numBytesRead = 0; 
    BOOL fileLoadResult = ReadFile(fileHandle, (PVOID)buffer, fileSizeResult, &numBytesRead, NULL); 

    // Import key 
    BOOL result = ImportKey(crypt_prov_hndl, (LPBYTE)buffer, numBytesRead); 
//result is always false.. 

답변

5

MSCAPI를 사용하는 경우 Microsoft 인증서 저장소에 키를 추가 한 것으로 간주됩니다. 사용 가능한 인증서 목록을 제공하는 "인터넷 속성"> "콘텐츠"> "인증서"로 이동하여 키가 있는지 확인할 수 있습니다. 인증서가 없으면 사용할 수 없습니다. 코드가 있으면 다음 코드가 필요합니다.

SunMSCAPI providerMSCAPI = new SunMSCAPI(); 
Security.addProvider(providerMSCAPI); 
KeyStore ks = KeyStore.getInstance("Windows-MY"); 
ks.load(null, null); 

코드는 꽤 표준 적입니다. 자세한 내용은 my book on digital signatures에 문의하십시오 (이 책은 무료입니다).

중요 추가 사항 : SunMSCAPI가 Java 6의 64 비트 버전에는 없습니다 (Java 7에 대해 잘 모름)라는 것을 잊었습니다. 32 비트 버전을 설치하여이 문제를 해결할 수 있습니다.

+0

답장을 보내 주셔서 감사합니다. 키 저장소를 만들기 위해 java keytool을 사용하고 코드에서 위에서 언급 한대로 Java 응용 프로그램의 키 저장소를 사용하여 공개 키를 내보내는 중, 해당 파일을 두 번 클릭해도 인증서 목록에 표시되지 않습니다. 자체 서명 된 인증서를 추가 할 수있는 방법을 제공 할 수 있습니까? – Ali

+0

첫 번째 질문 : JKS 키가 작동하지 않는다고 생각합니다. .p12 파일을 만들어야합니다. 보통 파일을 두 번 클릭하지 않고 인증서 개요로 이동 한 다음 키를 수동으로 가져옵니다. 그렇게하면 어떤 일이 발생하는지 정확하게 알 수 있습니다. –

+0

OK! java keytool을 사용하여 .p12 파일을 만들고 Windows 인증서에 설치했습니다. 모두 잘 작동합니다 Signature.getInstance ("SHA1withRSA", "SunMSCAPI")를 사용하여 파일에 서명 할 수 있지만 여전히 공개 키 (위의 코드에서 언급 한)를 가져올 수 없습니다. MS Crypto API를 사용하여 생각합니다. 큰/작은 엔디안 형식의 문제. – Ali