2012-03-15 5 views
0

는 다음과 같은 XMLDSig 프로 문서 SignedInfo에 가정을위한 RSA-SHA1 서명을 생성하기 위해 Windows 암호화 API를 사용하는 방법 :XMLDSIG

<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod> 
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod> 
    <Reference URI="#object"> 
    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
    <DigestValue>OPnpF/ZNLDxJ/I+1F3iHhlmSwgo=</DigestValue> 
    </Reference> 
</SignedInfo> 

위의 SignedInfo에 노드의 SHA1이

5a c8 ef ab 04 5a 9a 46 fe 00 1a c5 8c 25 36 46 ff 88 dc 6a 

가 발생하는 것입니다 Windows CryptoAPI의 SignatureValue에서 다음을 실행합니다.

var hProv: HCRYPTPROV; 
    hHash: HCRYPTHASH; 
    hKey: HCRYPTKEY; 
    s: string; 
    B, bSign: TBytes; 
    bPrefix, bPubKeyModulus, bExp: TBytes; 
    iFFLen, iPos, iSize, iHashSize: Cardinal; 
    PubKey: TRsaPubKey; 
begin 
    s := '<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">' + #$0A + 
     ' <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>' + #$0A + 
     ' <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>' + #$0A + 
     ' <Reference URI="#object">' + #$0A + 
     ' <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>' + #$0A + 
     ' <DigestValue>OPnpF/ZNLDxJ/I+1F3iHhlmSwgo=</DigestValue>' + #$0A + 
     ' </Reference>' + #$0A + 
     '</SignedInfo>'; 

    B := TEncoding.ANSI.GetBytes(s); 

    {get context for crypt default provider} 
    Win32Check(CryptAcquireContext(hProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)); 
    try 
    Win32Check(CryptGenKey(hProv, AT_SIGNATURE, RSA1024BIT_KEY or CRYPT_EXPORTABLE or ALG_SID_RSA_PKCS, hKey)); 

    {create hash-object (SHA algorithm)} 
    Win32Check(CryptCreateHash(hProv, CALG_SHA1, 0, 0, hHash)); 

    Win32Check(CryptHashData(hHash, @B[0], Length(B), 0)); 

    // Obtain hash size 
    iSize := SizeOf(iSize); 
    SetLength(B, iSize); 
    Win32Check(CryptGetHashParam(hHash, HP_HASHSIZE, @B[0], iSize, 0)); 
    Move(B[0], iSize, iSize); 

    // obtain hash value 
    SetLength(B, iSize); 
    Win32Check(CryptGetHashParam(hHash, HP_HASHVAL, @B[0], iSize, 0)); 

    Print('Hex: ' + ToHex(B)); 
    Print('Base64: ' + ToBase64(B)); 

    // Signature of Hash 
    Win32Check(CryptSignHash(hHash, AT_SIGNATURE, nil, 0, nil, iSize)); 
    SetLength(bSign, iSize); 
    Win32Check(CryptSignHash(hHash, AT_SIGNATURE, nil, 0, @bSign[0], iSize)); 

    Print; 
    Print('Signature: '); 
    Print(ToBase64(Reverse(bSign))); 

    // Public key 
    Win32Check(CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, nil, iSize)); 

    SetLength(B, iSize); 
    Win32Check(CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, @B[0], iSize)); 

    Print; 
    Print('Public Key: '); 
    Print(ToHexASCII(B)); 

    Move(B[SizeOf(TPublicKeyStruc)], PubKey, SizeOf(PubKey)); 

    // Public key: Get Modulus 
    SetLength(bPubKeyModulus, PubKey.bitlen div 8); 
    Move(B[SizeOf(TPublicKeyStruc) + SizeOf(TRsaPubKey)], bPubKeyModulus[0], Length(bPubKeyModulus)); 
    Print; 
    Print('Modulus: '); 
    Print(ToHex(bPubKeyModulus)); 
    Print; 
    Print(ToBase64(bPubKeyModulus)); 

    // Public key: Get Exponent 
    Print; 
    Print('Exponent: '); 
    Print(IntToStr(PubKey.pubexp)); 
    SetLength(bExp, SizeOf(PubKey.pubexp)); 
    Move(PubKey.pubexp, bExp[0], Length(bExp)); 
    while bExp[Length(bExp) - 1] = 0 do 
     SetLength(bExp, Length(bExp) - 1); 
    Print('Base64: ' + ToBase64(bExp)); 

    Print; 
    if CryptVerifySignature(hHash, @bSign[0], Length(bSign), hKey, nil, 0) then 
     Print('signature verified') 
    else 
     RaiseLastOSError; 

    Win32Check(CryptDestroyKey(hKey)); 

    {destroy hash-object} 
    Win32Check(CryptDestroyHash(hHash)); 
    finally 
    {release the context for crypt default provider} 
    Win32Check(CryptReleaseContext(hProv, 0)); 
    end; 
end; 

서명을 생성하고 인증 할 수 있습니다. n CryptoAPI XMLDSig 사양에 따라 수행 중인지 확실하지 않습니다. http://www.aleksey.com/xmlsec/xmldsig-verifier.html

나는 다음과 같은 XMLDSig 프로 문서의 계수와 SignatureValue를 교체하고 온라인 검증과 확인 :

<?xml version="1.0" encoding="UTF-8"?> 
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod> 
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod> 
    <Reference URI="#object"> 
    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
    <DigestValue>OPnpF/ZNLDxJ/I+1F3iHhlmSwgo=</DigestValue> 
    </Reference> 
</SignedInfo> 
<SignatureValue>nihUFQg4mDhLgecvhIcKb9Gz8VRTOlw+adiZOBBXgK4JodEe5aFfCqm8WcRIT8GLLXSk8PsUP4//SsKqUBQkpotcAqQAhtz2v9kCWdoUDnAOtFZkd/CnsZ1sge0ndha40wWDV+nOWyJxkYgicvB8POYtSmldLLepPGMz+J7/Uws=</SignatureValue> 
<KeyInfo> 
    <KeyValue> 
    <RSAKeyValue><Modulus>4IlzOY3Y9fXoh3Y5f06wBbtTg94Pt6vcfcd1KQ0FLm0S36aGJtTSb6pYKfyX7PqCUQ8wgL6xUJ5GRPEsu9gyz8ZobwfZsGCsvu40CWoT9fcFBZPfXro1Vtlh/xl/yYHm+Gzqh0Bw76xtLHSfLfpVOrmZdwKmSFKMTvNXOFd0V18=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue> 
    </KeyValue> 
</KeyInfo> 
<Object xmlns="http://www.w3.org/2000/09/xmldsig#" Id="object">some text 
    with spaces and CR-LF.</Object> 
</Signature> 
내가 바로 그 일을하고있는 경우

더 확인하기 위해, 나는 온라인 검증을 시도

그리고 분명히 실패합니다.

나는 서명 값을 정확하게 생성하지 못했다고 생각합니다.

답변

1

마침내 작업이 완료되었습니다. 마침내 엔디안 문제였습니다. Microsoft CryptoAPI는 Little Endian 비트 문자열에 계수 및 서명 값을 표시합니다. XMLDSIG 사양은 Big Endian 비트 문자열로 제공됩니다.

function Reverse(A: TBytes): TBytes; 
var B: Byte; 
    i: integer; 
begin 
    SetLength(Result, Length(A)); 
    i := Length(A) - 1; 
    for B in A do begin 
    Result[i] := B; 
    Dec(i); 
    end; 
end; 

Print(ToBase64(reverse(bSign))); 
Print(ToBase64(reverse(bPubKeyModulus))); 
:

의 CryptoAPI 함수에서 계수 및 서명 값을 얻은 후에, 바로 바이트 순서를 반전하여 빅 엔디안 비트 문자열로 변환

1

네이티브 코드와 XML이 아닌 XMLDSig 문서를 확인해야한다면 MSXML 5.0을 사용하는 것이 좋습니다. 서명을 확인하려면 the code example을 참조하고 서명을 생성하려면 another one을 참조하십시오.