Click here to Skip to main content
Click here to Skip to main content

Cryptography in .NET

By , 9 Oct 2002
 

Overview

Windows provides a Public Key Infrastructure (PKI) that allows us to store certificates for encryption purposes. To access the this store we had two possibilities in the unmanaged past: The CryptoAPI and the CAPICOM.

The Framework Class Library (= FCL) provies a lot of function for encryption, but the current release doesn't provide any classes for accessing the the certificate store. Fortunately a the Web Services Development Kit (WSDK) Technology Preview adds this functionality; later this will be included in the FCL itself. But in the mean time you have to download the WSDK.

Enumerating The Certificate Store

The article Using WS-Security with the Web Services Development Kit Technology Preview has this nice example:
using Microsoft.WSDK.Security.Cryptography;
using Microsoft.WSDK.Security.Cryptography.X509Certificates;
  ...
private X509CertificateStore store;
  ...
private void Form1_Load( object sender, System.EventArgs e )
{
    store = X509CertificateStore.CurrentUserStore( X509CertificateStore.MyStore );
    store.OpenRead();
    foreach( X509Certificate cert in store.Certificates )
    {
        listBox1.Items.Add( cert.GetName() );
    }
}

Asymmetric Encryption/Signature Example

The following code is the funcionallity of my submitted example. It assumes that you have at least two certificates (with private key!) in your Personal Certificate Store.

try
{

   // GENERAL CODE TO READ THE CERTIFICATES FROM THE WINDOWS PKI INFRASTRUCTURE
   //
   // BEGINNER-TIP: Start MMC (=Microsoft Management Console) and select "Add-in/remove Snapin"
   // from the "Console" menu. Now press "Add.." button. Select "Certificates" in the list and
   // press "Add" button. You have the choise to select "My user account" or "Computer account".
   // Then press "Finish" and "Close" and start exploring the installed certificates... 
   // Each store has a "Personal" section with is BTW represented by the letters "MY".
   // Also interessting is the "Trusted root" certificates, there you see all the Certificate
   // Issuer that you trust, there is quite a lot and sometimes it's a good idea to delete
   // all of them and only add the one you need or really trust, for security resasons.
   //

   // Open private certificate store of current user

   X509CertificateStore store = 
               X509CertificateStore.CurrentUserStore( X509CertificateStore.MyStore );
   store.OpenRead();

   // Read e.g. the first two certificate
   X509Certificate sender = (X509Certificate)store.Certificates[0];
   X509Certificate receiver = (X509Certificate)store.Certificates[1];

   // Let's see who we are dealing with... - ps: not nessesary for the following code
   string sender_serial = sender.GetName();
   string receiver_serial = receiver.GetName();


   //
   // SENDER-SIDE CODE
   //

   // SENDER-SIDE: Extract own private keys and receiver's public key

   RSAParameters sender_private = sender.Key.ExportParameters( true );
   RSAParameters receiver_public = receiver.Key.ExportParameters( false );

   // SENDER-SIDE: Asymmetric encryption with receivers's public key
   RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
   rsa.ImportParameters( receiver_public ); 
   byte[] cleartext = ASCIIEncoding.ASCII.GetBytes("test");
   byte[] cipher = rsa.Encrypt( cleartext, false );
   
   // SENDER-SIDE: Sign the cipher with own private key
   rsa = new RSACryptoServiceProvider();
   rsa.ImportParameters( sender_private );
   byte[] signature = rsa.SignData( cipher, new SHA1CryptoServiceProvider() );

   //
   // TODO: TRANSFER DATA OVER UNSECURE CHANNEL...
   //

   // RECEIVER-SIDE: Get own private key and sender's public key

   RSAParameters receiver_private = receiver.Key.ExportParameters( true );
   RSAParameters sender_public = sender.Key.ExportParameters( false );


   // RECEIVER-SIDE: Verify signature with sender's public key
   //
   // Note: You are ONLY verifying the signature and NOT verifying the Certificate!
   // It's corresponding to the CAPICOM call SignedData.Verify( CAPICOM_VERIFY_SIGNATURE_ONLY )
   // I did not yet find out how we can use the .NET library to verify the Certificate
   // against the issuer-chain. If someone knows how to do this, and not using interop
   // and the SignedData.Verify( CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE ), I would be
   // very, very, very happy - because this is a requirement in the software I'm developing
   // currently and if we can't do that I have to do CAPI-interop :-(
   // At the moment I think that there is no simple function call for this and this s***s.
   // Maybe it's possible to walk throw the chain-of-issuers and validate the fingerprint
   // this the public key of the issuer. But I don't know enough about that....
   // ANY HELP TO THIS POINT IS MORE THAN WELCOME
   //

   rsa = new RSACryptoServiceProvider();
   rsa.ImportParameters( sender_public );
   if( rsa.VerifyData( cipher, new SHA1CryptoServiceProvider(), signature ) )
   {
      // RECEIVER-SIDE: Asmymetirc decryption with own private key
      rsa.ImportParameters( receiver_private );
      byte[] cleartext_after_decription = rsa.Decrypt( cipher, false );

      // Check result
      Debug.Assert( ASCIIEncoding.ASCII.GetString( cleartext ) ==
         ASCIIEncoding.ASCII.GetString( cleartext_after_decription ),
         "Ups, the cleartext input is not equal the cleartext output..." );
   }
   else
      Debug.Assert( false, "Ups, check signature failed!" );
}
catch( Exception e )
{

   // NOTE: the following exception, that may occure during 'ExportParameters( true )'
   //
   //   System.Security.Cryptography.CryptographicException
   //   "Key information could not be exported from the cryptographic service 
   //    provider (CSP) for this implementation." }"
   // 
   // Can have one of the following reasons:
   // + The certificate was NOT imported with the flag "Mark the private key as exportable"
   // + The type "SSL Server Authentication(40)" and is in a CurrentUser store and not in
   //   the LocalComputer store. See certificate details in the MMC under "NetscapeCertType".
   //   IMHO: This reason is very wicked and I don't understand it!!


   Debug.Assert( false, e.ToString() );
}

Note: The X509Certificate class provides the function ExportParameters and the boolean parameter defines if the private key has to be submitted as well.

A quick note

Favorite person names for encryption examples are Alice, Bob and mean Steve. If you like to see how they are doing in .NET, search your MSDN examples for the excellent example file called PublicKey.cs!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Manuel Permuy
Web Developer
Switzerland Switzerland
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralProblem signing a serilized object using CAPICOM.SignedDatamemberEscroto5 Aug '04 - 23:54 
WTF | :WTF: Hello,
i am developing a web service which needs to sign serialized objects using CAPICOM.SignedData. Once i sign the object (serialized) i got from the CAPICOM.SignedData.Sign() method a string containing a PKCS#7 structure wich i send to the client.
 
In the client side i build a new CAPICOM.SignedData object to use its Verify method in order to get the content of the PKCS#7 structure (and with verifications aims). Since now it is impossible to deserialized the object.
 
Please help me!Confused | :confused:
 

GeneralRe: Problem signing a serilized object using CAPICOM.SignedDatamemberManuel Permuy6 Aug '04 - 13:10 
What's the error message (and number 08x????), when you call Veryfy?
 
To get to the source of the problem, try this:
--> Does it work when Can you call Veryfy()immediatley after Sign() --> If Yes, then the transport corrups the data...
 

GeneralRe: Problem signing a serilized object using CAPICOM.SignedDatamemberEscroto6 Aug '04 - 21:28 
In the server side, if i call Verify() inmediately after Sign() everithing goes all right. When the data arrive to the client and the verification is going to be done the exception System.IO.FileNotFoundException is thrown. Maybe the data are corrupted in the transport but o don´t think so because i can extract the certificates from the PKCS#7 structure.
GeneralRe: Problem signing a serilized object using CAPICOM.SignedDatamemberManuel Permuy9 Aug '04 - 3:26 
Might be the cretificates needed (private receiver or the one of the certificate issuer!) is not installed in the Windows Certificate Store (in the right place)...

Generalx509certficatestorememberLucia Melotti22 Apr '04 - 2:33 
HI!
I read your exemples in this web page.
I have to get the server'certificate from the CA store, and I would like to retrieve the public Key, I wrote:
 
x509store = x509store.CurrentUserStore("CA")
x509store.OpenRead()
x509cert = x509store.Certificates(0)
server_public = x509cert.Key.ExportParameters(False)
 
the problem is that in the server certiicate (x509cert)there are not informatin about the public key. The last instruction return error!!
Please cuold you help me?!?!?

 
Lucia Melotti
GeneralCAPICOM+CDOmemberrayback_29 Dec '03 - 7:13 
I am no expert in cryptography , but I had to do the digital signing of emails for some purpose I wrote the code below which constructed message usind CDO and then signed data to be sent with CAPICOM and then send teh data. Well the problem is : when I send email using code below it says "Message has been tampered with" , though there's no such thing of course ( at least while trying it). I guess I am doing something wrong with conversions but cant be sure, except that error message all other things work ok, mean certificate is verified against chain and etc.. but as I said the digitally signed message I send seems to be corrupted.If anyone can help I will be very pleased.
   Ur sincerely Ray
 
Here is the code
//***************************************************************************
 
CDO.MessageClass a = new CDO.MessageClass();
CDO.IBodyPart ibp;
CDO.IBodyPart ibp2;         
ADODB.Fields flds;
    
a.To = tbTo.Text ;
a.From = "someone@eomewhere.com";
a.Subject = tbKonu.Text.Trim();
 

a.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"].Value   = CdoSendUsing.cdoSendUsingPort;
 
a.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserver"].Value   = "MAILSERVERNAME";
a.Configuration.Fields.Update();
 
ibp = a;
flds = ibp.Fields;
a.MimeFormatted = true;
 
flds["urn:schemas:mailheader:Content-Type"].Value = "multipart/signed; protocol=application/x-pkcs7-signature; micalg=SHA1";
flds["urn:schemas:mailheader:thread-index"].Value = "";
flds["urn:schemas:mailheader:thread-topic"].Value = "";
flds["urn:schemas:mailheader:priority"].Value = "";
flds["urn:schemas:mailheader:importance"].Value = "";
flds["urn:schemas:mailheader:content-class"].Value = "";
 

flds["urn:schemas:mailheader:Content-Language"].Value ="tr";
flds["urn:schemas:mailheader:charset"].Value ="Cp1254";
 

flds.Update();
    
 
// Setup the first body part; this is the header
// plus the file contents.
 
ibp2 = a.AddBodyPart(1);
flds = ibp2.Fields;
 
flds["urn:schemas:httpmail:content-media-type"].Value   = "text/plain";
flds["urn:schemas:mailheader:content-type"].Value = "text/plain; charset=UTF-8";
flds["urn:schemas:mailheader:content-class"].Value   = "urn:content-classes:message";
flds["urn:schemas:mailheader:content-transfer-encoding"].Value   = "7bit";
flds.Update();
 
ADODB.Stream stm;
string strbase64;
 
string msgtosign = tbMAIL.Text;
stm = ibp2.GetDecodedContentStream();
stm.Type = ADODB.StreamTypeEnum.adTypeText;
stm.WriteText(msgtosign, ADODB.StreamWriteEnum.adWriteChar);
 
stm.Flush() ;
 
CAPICOM.StoreClass d1 = new CAPICOM.StoreClass();
CAPICOM.Certificate cert;
cert = null;
 

d1.IStore_Open(CAPICOM_STORE_LOCATION.CAPICOM_CURRENT_USER_STORE,"MY",CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_READ_ONLY);
 
foreach(CAPICOM.Certificate   ff in d1.Certificates)
{
     list1.Items.Add(ff.GetInfo(CAPICOM_CERT_INFO_TYPE.CAPICOM_CERT_INFO_SUBJECT_EMAIL_NAME ));
 
     cert = ff;
}
 
CAPICOM.SignerClass osigner = new SignerClass();
CAPICOM.AttributeClass oattr = new AttributeClass();
 
osigner.Certificate = cert;
 
oattr.Name = CAPICOM_ATTRIBUTE.CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME ;
oattr.Value = DateTime.Now;
 
osigner.AuthenticatedAttributes.Add(oattr);
 
CAPICOM.SignedDataClass osigneddata = new SignedDataClass();
osigneddata.Content = ibp2.GetStream().ReadText(ibp2.GetStream().Size);
 
strbase64 = osigneddata.Sign(osigner,true, CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BASE64);
 
//verifying certificate!!!!! IS IT OK TO USE IT LIKE THIS
try
{
     osigneddata.Verify(strbase64, true,CAPICOM_SIGNED_DATA_VERIFY_FLAG.CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE);
}
catch(System.Exception e1)
{
     Response.Write(e1.ToString());
     Response.Write("\n");
     Response.Write("Sertifika bilgileri Eksik veya Sertifika Bulunamadı");
}
 
//CAPICOM
 
ibp2 = a.AddBodyPart(2);
flds = ibp2.Fields;
 
flds["urn:schemas:mailheader:Content-Type"].Value   = "application/x-pkcs7-signature; Name = smime.p7s";
flds["urn:schemas:mailheader:Content-Transfer-Encoding"].Value   = "base64";
flds["urn:schemas:mailheader:content-Disposition"].Value   = "attachment; FileName = smime.p7s";
flds["urn:schemas:mailheader:content-Description"].Value   = "S/MIME Cryptographic Signature";
flds.Update();
 

stm = ibp2.GetEncodedContentStream();
stm.Type = ADODB.StreamTypeEnum.adTypeText;
stm.WriteText(strbase64,ADODB.StreamWriteEnum.stWriteLine);
stm.Flush();    
 

a.Send();
 
//***************************************************************************

GeneralRe: CAPICOM+CDOmemberrayback_223 Dec '03 - 23:17 
Ok I have solved the problem that I sketched aove, the problem was with encoding. Now I can sign and send messages, but I cant send the Signed(message+attachment) , that is text and attachment I want to sign , but it gives me "the message has been trampered with" staff, so tell me what am I to do?
GeneralRe: CAPICOM+CDOsussgoayeh21 Apr '05 - 16:19 

I tried this code , either,
 
when I open the mail , It's told me:
 
" The Mail have changed "
 
what happens ? The source mail as follows:
 
charset: big5
From: "Me"
To: "You"
Subject: Here is a signed message
MIME-Version: 1.0
Content-Type: multipart/signed;
protocol="application/x-pkcs7-signature";
micalg=SHA1;
boundary="----=_NextPart_000_0005_01C54724.55C4C200"
Content-Transfer-Encoding: 7bit
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.3790.224
 
This is a multi-part message in MIME format.
 
------=_NextPart_000_0005_01C54724.55C4C200
Content-Class: urn:content-classes:message
Content-Type: text/plain;
charset="UTF-8"
Content-Transfer-Encoding: 8bit
 
aaaaaa?皜祈岫aaaaaaaaa
------=_NextPart_000_0005_01C54724.55C4C200
Content-Disposition: attachment;
filename="smime.p7s"
Content-Description: S/MIME Cryptographic Signature
Content-Type: application/x-pkcs7-signature;
name="smime.p7s"
Content-Transfer-Encoding: base64
 
嚜燐IIJJQYJKoZIhvcNAQcCoIIJFjCCCRICAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
DQEHAaCCB3kwggd1MIIGXaADAgECAgobM/KUAAAAAAAFMA0GCSqGSIb3DQEBBQUA
.............................................................much
Yq6jn+hyopSqGCQbJ46nJzT7tKWe+U+3XdCQww8F+hb523KEGWHpnn0GXkDDjFtQ
DdGx7VSGk77BdUrlJiFtJ2wG7QwB1++9aUXG9GgW6jq5/G420mE56W4=
 
------=_NextPart_000_0005_01C54724.55C4C20
 


GeneralRe: CAPCIOM+CDO SendSignedMailmemberrayback_221 Apr '05 - 21:19 
Hi friend .I faced the same problem ,I remember struggling with line endings for a long time (it seemed that I put one extra line ending Smile | :) ).
I send here the modified code of what I wrote before and its code (at least work here ) hope it helps.
Sincerely Ray

Const cdoSendUsingPickup = 1
Const cdoSendUsingPort = 2
 
Const cdoBasic = 1
 
const CAPICOM_STORE_OPEN_READ_ONLY = 0
const CAPICOM_CURRENT_USER_STORE = 2
const CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0
const CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY = 6
const CAPICOM_CERTIFICATE_FIND_TIME_VALID = 9
const CAPICOM_CERTIFICATE_FIND_KEY_USAGE = 12
const CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0
const CAPICOM_INFO_SUBJECT_SIMPLE_NAME = 0
const CAPICOM_CERT_INFO_SUBJECT_EMAIL_NAME = 2
const CAPICOM_ENCODE_BASE64 = 0
const CAPICOM_ENCODE_BINARY = 1
const CAPICOM_E_CANCELLED = -2138568446
const CERT_KEY_SPEC_PROP_ID = 6
 
Const vbFromUnicode = 128
Const vbUnicode = 64

Const cdoIMessage = "IMessage"
'*****************************************************************************************
'*********** Send Signed email Message **************************
'***********Attachments if any are given as comma separated paths (physical paths of the file)**
'*****************************************************************************************
Public Function SendSignedMail(ByVal fromstr, ByVal tostr , ByVal subjectstr , ByVal bodystr , ByVal Attchmnt)

Set oSignedMsg = CreateObject("CDO.Message")
Set oSignedData = CreateObject("CAPICOM.SignedData")
Set oUtilities = CreateObject("CAPICOM.Utilities")
Set oAttribute = CreateObject("CAPICOM.Attribute")
set oStore = CreateObject("CAPICOM.Store")
set oSigner = CreateObject("CAPICOM.Signer")
set oReciepents = CreateObject("CAPICOM.Certificates")
Dim szNames
 

' select the signer certificate
oStore.Open CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY
Set cSignerCertificates = oStore.Certificates

Select Case cSignerCertificates.Count
Case 0
MsgBox "No certificate found"
Exit Function
Case 1
oSigner.Certificate = cSignerCertificates(1)
Case Else
Set cSignerCertificates = cSignerCertificates.Select("Certificates", "Select certificate for signing")
If (cSignerCertificates.Count = 0) Then
msgbox "Error : Certificate selection canceled"
Exit Function
End If
oSigner.Certificate = cSignerCertificates(1)
End Select
 
'assign certificate chosen by user to object for signing
SelectCertificate = oSigner.Certificate.GetInfo(CAPICOM_CERT_INFO_SUBJECT_EMAIL_NAME)

'set the signing time in UTC time
oAttribute.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME
oAttribute.Value = oUtilities.LocalTimeToUTCTime(Now)



oSigner.AuthenticatedAttributes.Add oAttribute

'REGION ATTACHMENTS

'if there are no attachments

If Len(Trim(Attchmnt)) = 0 Then
Set oBodyPart = oSignedMsg.BodyPart.AddBodyPart
Set cFields = oBodyPart.Fields
cFields.Item("urn:schemas:mailheader:content-type") = "text/html"
cFields.Update

Set oStream = oBodyPart.GetDecodedContentStream
oStream.WriteText bodystr
oStream.Flush
End If

'if there are attachments

If Len(Trim(Attchmnt)) <> 0 Then

'add text part
Set oBodyPart = oSignedMsg.BodyPart.AddBodyPart
Set cFields = oBodyPart.Fields
cFields.Item("urn:schemas:mailheader:content-type").Value = "multipart/mixed;boundary=MIXEDBOUNDARY"
cFields.Update

Set oBodyPart = oSignedMsg.BodyPart.BodyParts(1).AddBodyPart
Set cFields = oBodyPart.Fields
cFields.Item("urn:schemas:mailheader:content-type") = "text/html"
cFields.Update

Set oStream = oBodyPart.GetDecodedContentStream
oStream.WriteText bodystr
oStream.Flush

'add attachments , the paths to attached files are separated by comma
Dim ekler
Dim ekcikler
Dim i
ekler = Split(Attchmnt, ",")

'replace \ character with /
For i = 0 To UBound(ekler)
ekcikler = Split(ekler(i), "\")
ekler(i) = Join(ekcikler, "/")
Next

For i = 0 To UBound(ekler)
Set oBodyPart = oSignedMsg.BodyPart.BodyParts(1).AddBodyPart
Set cFields = oBodyPart.Fields
cFields.Item("urn:schemas:mailheader:content-type").Value = "application/octet-stream" & vbCrLf & "Name = """ & ekler(i) & """"
cFields.Item("urn:schemas:mailheader:content-transfer-encoding").Value = "base64"
cFields.Item("urn:schemas:mailheader:content-disposition").Value = "attachment;" & vbCrLf & "FileName=""" & ekler(i) & """"
cFields.Update

Set oStream = oBodyPart.GetDecodedContentStream
oStream.LoadFromFile ekler(i)
oStream.Flush
Next

End If


'ENDREGION ATTACHMENT

ss = oSignedMsg.BodyPart.BodyParts(1).GetStream.ReadText
ss = Replace(ss, "This is a multi-part message in MIME format." + vbCrLf, "")



oSignedData.Content = StrConv(ss, 128)
 

' sign the content
dim szSignature
szSignature = oSignedData.Sign(oSigner, True, CAPICOM_ENCODE_BINARY)
byteSignature = oUtilities.BinaryStringToByteArray(szSignature)

' Attach the signature and let CDO base64 encode it
Set oBodyPart = oSignedMsg.BodyPart.AddBodyPart
Set cFields = oBodyPart.Fields
oBodyPart.Fields.Item("urn:schemas:mailheader:content-type").Value = "application/x-pkcs7-signature" & vbCrLf & "Name = ""smime.p7s"""
oBodyPart.Fields.Item("urn:schemas:mailheader:content-transfer-encoding").Value = "base64"
oBodyPart.Fields.Item("urn:schemas:mailheader:content-disposition").Value = "attachment;" & vbCrLf & "FileName=""smime.p7s"""
cFields.Update

Set oStream = oBodyPart.GetDecodedContentStream
oStream.Type = 1
oStream.Write(byteSignature)
oStream.Flush

' Set the messages content type, this needs to be done last to ensure it is not changed when we add the BodyParts
oSignedMsg.Fields.Item("urn:schemas:mailheader:content-type").Value = "multipart/signed;" & vbCrLf & "protocol=""application/x-pkcs7-signature"";" & vbCrLf & "micalg=SHA1;boundary=SIGNEDBOUNDARY"
oSignedMsg.Fields.Update
 
' Signing Was sucessfull
SignMessage = True

' set the from field based off of the selected certificate
oSignedMsg.From = oSigner.Certificate.GetInfo(CAPICOM_CERT_INFO_SUBJECT_EMAIL_NAME)
oSignedMsg.To = tostr
oSignedMsg.Subject = subjectstr
oSignedMsg.Fields.Update

'set sending parameters
oSignedMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing").Value = cdoSendUsingPort
oSignedMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value = "MAILSERVERADRESS"
oSignedMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport").Value = 25
oSignedMsg.Configuration.Fields.Update

'send message
oSignedMsg.Send
 
msgbox "Message succesfully sent"

End Function
 

'*****************************************************************************************
'*********** UNICODE to ASCII and BACK **************
'****************************************************************************
Public function StrConv(ByRef stringData, ByRef conversion)
Dim Stream
Set Stream = CreateObject("ADODB.Stream")
 
Const UnicodeCharaset = "Windows-1252"
Const BinaryCharset = "X-ANSI"
Select Case conversion
Case vbFromUnicode
' UNICODDAN ASCII'ye CEVIRME
With Stream
.Charset = UnicodeCharaset
.Type = 2
.Open
.WriteText stringData
.Position = 0
.Charset = BinaryCharset
.Type = 1
StrConv = MidB(.Read, 1)
End With

Case vbUnicode
' ASCII DEN UNICODA CEVIRME
Dim Length
Dim Buffer

if TypeName(stringData) = "Null" Then
CStrU = ""
Exit function
End if

stringData = MidB(stringData, 1)

Length = LenB(stringData)
Dim Rs
Set Rs = CreateObject("ADODB.Recordset")
Call Rs.Fields.Append("BinaryData", adLongVarBinary, Length)
Rs.Open
Rs.AddNew
Rs.Fields("BinaryData").AppendChunk(stringData & ChrB(0))
Rs.Update
Buffer = Rs.Fields("BinaryData").GetChunk(Length)
Rs.Close
Set Rs = Nothing
With Stream
.Charset = BinaryCharset
.Type = 1
.Open
Call .Write(Buffer)
.Position = 0
.Type = 2
.Charset = UnicodeCharaset
End With

StrConv = Stream.ReadText(-1)
End Select
Stream.Close
Set Stream = Nothing
End function

GeneralRe: CAPCIOM+CDO SendSignedMailmemberNoradYeh26 Apr '05 - 22:12 
Hi, Sir,
 
I tried your code several days,
 
but the function 'StrConv' is VB6's code,
 
I tried change it to vb.net, but failed....
 
could you help me if you have free time ...
 
Thank you very much !
GeneralRe: CAPCIOM+CDO SendSignedMailmemberrayback_226 Apr '05 - 22:26 
Hi.
 
Yes as u said the StrConv is the built in of VB 6.0 and it wont work for vbscript and vb.net (though in vb.net you have counterpart for that function doing the same thing).
I sent the vbscript version of the function too in the code I submitted previously (at the bottom of the page maybe u missed that). What it does is this : using the ADODB stream it converts the unicode characters to ascii and back. You should use that custom function in vbscript code because the built in StrConv is not available in vbscript (at least its how I know it to be)
 
Here I resent the function definition for StrConv
 
Const vbFromUnicode = 128
Const vbUnicode = 64
 
'*****************************************************************************************
'*********** From Unicode to ASCII and Back**************
'*****************************************************************************************
Public function StrConv(ByRef stringData, ByRef conversion)
Dim Stream
Set Stream = CreateObject("ADODB.Stream")
 
Const UnicodeCharaset = "Windows-1252"
Const BinaryCharset = "X-ANSI"
Select Case conversion
Case vbFromUnicode
' from unicode to ascii
With Stream
.Charset = UnicodeCharaset
.Type = 2
.Open
.WriteText stringData
.Position = 0
.Charset = BinaryCharset
.Type = 1
StrConv = MidB(.Read, 1)
End With

Case vbUnicode
' from ascii to unicode
Dim Length
Dim Buffer

if TypeName(stringData) = "Null" Then
CStrU = ""
Exit function
End if

stringData = MidB(stringData, 1)

Length = LenB(stringData)
Dim Rs
Set Rs = CreateObject("ADODB.Recordset")
Call Rs.Fields.Append("BinaryData", adLongVarBinary, Length)
Rs.Open
Rs.AddNew
Rs.Fields("BinaryData").AppendChunk(stringData & ChrB(0))
Rs.Update
Buffer = Rs.Fields("BinaryData").GetChunk(Length)
Rs.Close
Set Rs = Nothing
With Stream
.Charset = BinaryCharset
.Type = 1
.Open
Call .Write(Buffer)
.Position = 0
.Type = 2
.Charset = UnicodeCharaset
End With

StrConv = Stream.ReadText(-1)
End Select
Stream.Close
Set Stream = Nothing
End function
 

Sincerely Ray
 

P.S: also u can convert the code to vb.net but, theres a big but in that not technically but in principle. If you are writing a web application the certificate you are trying to access is on client machine and not server. So the only solution I saw is to write a script for it, because theres no way of bringing the certificate (wth the private key) to server (its not right thing to do ). So I guess if u are writing the web application you should do it in script.
 

GeneralRe: CAPCIOM+CDO SendSignedMailmemberabygm2 Nov '07 - 2:15 
Hi Ray..,
 
I am facing error when signing mail with embedded image. To embed image, it need to be a Part of the main body. If you put it as a Part of a Subpart (I mean, it should be oSignedMsg.BodyPart.AddBodyPart and not oSignedMsg.BodyPart.BodyParts(1).AddBodyPart) it will embed as well as show as an attachment.
 
Issue is, if we put image as part of a subpart signing is fine; Outlook validates it. Problem is it will embed the image as well as show it as an attachment. If we put it as part of body, signing fails; It is not recognised as a signed message.
 
Can you throw some light..?
 
Regards,
 
Aby.
Generaluse phone numbermembersmail belmokhtar19 Nov '03 - 1:51 
please i neede to this tips..
 
i neede how to communicate tow application (client-server)
by the phone number without using the internet
                                             thunks
QuestionWhich page is main source?memberStefan Pedersen3 Oct '03 - 11:07 
http://users.pandora.be/ahmadi/html/security.html[^]
 
This page is identical to your article and I wonder which page is to be considered the main source? There are no references on either to the other.
AnswerRe: Which page is main source?memberManuel Permuy5 Oct '03 - 7:03 
I'm the author of this article, so the other is a copy...
 
Some things changed and I quess it's about time to update this article anyway. Stay tuned Wink | ;-)
Generalyour URL to WSDK is brokenmembernorm25 Aug '03 - 21:29 
Good article, nice and short and to the point. One reminder, URL to "Web Services Development Kit (WSDK) Technology Preview" is broken.
 
Also, I can do all this without WSDK - using just System.Cryptography? I'm new to this. I am just looking for examples (.NET samples):
1. sign/hash/encrypt data (covered in this article)
- both PPK and classic symmetric algo.
2. Also want to know how to "publish" your public key so receiver decrypt payload and verify signature (in your sample, client and receiver on same machine/process.) So, am I talking about exporting key/key blob? A handle to a key is meaningless on a remote machine. (this is NOT covered in the article)
3. retrieve certificates from cert stores (covered in this article)
4. add cert (makecert.exe or MMC/3rd party: I'm alrite with this.)
 
Any good articles? I want to do this all .NET - but as you mentioned, you don't get .NET support in dealing with cert stores. Is that still true?
 
Thanks.
 
norm
GeneralWSDK becomes WSEsuss.Net wannabe6 Jun '03 - 14:53 
That's old news but I have a comment to make on the code above. If you don't export and do import your certificate key directly into RSA by using the code below to instantiate the RSACryptoServiceProvider class you overcome many problems (such as un-exporable keys).
 
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)sender.Key;
 

GeneralHelp neededmemberMBuuri22 May '03 - 3:07 
I have two things am puzzled with:
 
1. How do I extend this code to encrypting entire files intead of blocks of few bytes (limited by rsa.encrypt). Should I come up with a random key for 3DES, encrypt the file with that and then append the key as RSA encrypted?
 
2. The code doesn't work for smart cars where private keys are located at the chip. How do I change the CSP to smart card software vendor's CSP (that I have) or is there some other way to go?
 
Cheers!
GeneralRe: Help neededmemberMarcello Drewanz18 Jun '03 - 7:25 
Here are some info to the questions.
 
1.- You're right, RSA is not for huge amount of data. Use 3DES or other symmetric algorithm to encrypt the data and RSA to encrypt just the key.
 
2.- To change the CSP, you'll need to use the CspParameters.
 

CspParameters csp = new CspParameters();
 
csp.KeyContainerName = "KeyContainer";
csp.ProviderType = 1; // PROV_RSA_FULL;
csp.ProviderName = "Provider for SmartCard";
 
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
 

 

 
-marcello drewanz
GeneralYou get a 5...adminChris Maunder25 Feb '03 - 9:00 
...for your bio pic Big Grin | :-D
 
cheers,
Chris Maunder
General"I am Emmet Smith!"memberrflagg24 Feb '03 - 17:35 
I'm a newbee at encryption. I've got a task that I'm looking for advice on.
 
In my company, everyone was issued a unique certificate file (XXX.CER). What I need to do is :
1.) Read the certificate from the floppy drive. (Something like FCLX509.X509Certificate FCLcer = WSEX509.X509Certificate.CreateFromCertFile(@"A:\IAmEmmetSmith.cer")
 
2.) Extract the person's name. (Which I know how to do.)
3.) Make sure the certificate is valid. (Only 1 Emmet Smith with this particular certificate that works on our server.)
 
I don't know how to #3. Help!
 
I've seen sample code like this:
X509SecurityToken token = new X509SecurityToken(cer);
token.Verify();
but I imagine that I need to match the certificate file with the certificate on the server.
 
Any help would be greatly appreciated!
 
rflagg
 

GeneralRe: &quot;I am Emmet Smith!&quot;memberManuel Permuy4 Feb '04 - 13:48 
Sorry for not responding immediatley - I was in the *relese stress* for the last month - basically I still am but I stoped worrying...
 
Anyway, you still need help?
GeneralCertificate issuer chain...memberFred James11 Feb '03 - 2:13 
Hi manuel,
 
> how we can use the .NET library to verify the Certificate against the issuer-chain.
 
You can use the X509SecutityToken Verify Method.
"This method checks all the contained signatures signed by various parties"
 
X509SecutityToken token = new X509SecutityToken(certificate);
try{
token.Verify()
}
catch (Exception....
 

 
Fred
http://www.protek-lab.com
GeneralVerify the CertificatememberFred James11 Feb '03 - 2:12 
Hi manuel,
 
> how we can use the .NET library to verify the Certificate against the issuer-chain.
 
You can use the X509SecutityToken Verify Method.
"This method checks all the contained signatures signed by various parties"
 
X509SecutityToken token = new X509SecutityToken(certificate);
try{
token.Verify()
}
catch (Exception....
 

 
Fred
http://www.protek-lab.com
GeneralRe: Verify the CertificatememberWhyIamhere30 Apr '04 - 9:12 
I used the above code. It is failed to verify my self signed certificate. The certificate is created using the command "makecert -r -pe -cy both -n "CN=MyName" -ss Root
The error message is as following:
 
Microsoft.Web.Services.Security.SecurityFault: An invalid security token was pro
vided ---> System.Security.SecurityException: The certificates trust chain could
not be verified: CERT_CHAIN_POLICY_STATUS is 2148204809.
at Microsoft.Web.Services.Security.X509.X509CertificateChain.Verify()
at Microsoft.Web.Services.Security.X509SecurityToken.VerifyTrust()
at Microsoft.Web.Services.Security.X509SecurityToken.Verify()
--- End of inner exception stack trace ---
at Microsoft.Web.Services.Security.X509SecurityToken.Verify()
at Codeproject.Cryptography.CryptographyApp.VerifyCertificate(X509Certificate)
 
BTY, this article is very helpful. Thank you.
Wendy
GeneralCAPICOMmemberpoojavedi29 Jan '03 - 0:00 
I m trying to build a secure .NET web application using Digital certificates.
I created a couple of test certificates using makecert utlity. I also have CAPICOM installed on my PC.
Can someone suggest how I should proceed further?
What all needs to be done in order to send as well as receive secure data?
QuestionCAPICOM Necessary?memberSteveC881 Oct '02 - 8:45 
I am wondering if CAPICOM is still necessary. Right now I am doing COM+Interop to CAPICOM from C# because I have PKCS#12 (aka PFX) files in my personal store.
 
I take some data, use the private key in the PKCS#12 cert to sign it, and then use the receiver's public key in an X509 to envelope it. Then I dump it in a queue.
The receiver de-envelopes with the private key in their PKCS#12, and then uses the sender public key in an X509 to verify the signature.
 
Are you saying that this isn't necessary with the WSDK stuff and your code? It looks like the MS stuff only handles X509, which has no support for private keys. I am little confused.
 
Thanks.
AnswerRe: CAPICOM Necessary?memberManuel Permuy4 Oct '02 - 13:01 
YES it's possible, BUT:
 
-> The PKCS#12 certificate has to be imported with the flag
"Mark this certificate as exportable"
 
-> I didn't (yet) found out how to validate the certificate
against it's issuer (chain of certificates)
 
IF this are no requirements in your software, I can only say:
you Cool | :cool: are lucky and can use it - in my case I X|can't

GeneralThe X509Certificate class provides the function ExportParameterssussAnonymous28 Sep '02 - 7:20 
No the X509Certificate class doesn't provides ExportParameters.
But both RSA and DSA class (and descendant) do provide it.
GeneralRe: The X509Certificate class provides the function ExportParametersmemberManuel Permuy30 Sep '02 - 11:16 
That's true, for the X509Certificate class that is installed with .NET.
 
But this example uses Microsoft.WSDK.Security.Cryptography.X509Certificates.X509Certificate class that comes with WSDK (see link in the artilcle). After you installed the WSDK, you can import the WSDK-dll and use the Microsoft.WSDK.Security... namespace.
 
Note: To export the private key of a certificate, the certificate has to be marked as "exportable". This can be set during import of certificate with the MMC plugin.
 
Hope this helps.
 

GeneralRe: The X509Certificate class provides the function ExportParameterssussAnonymous6 Oct '02 - 3:56 
You missed the point (and made another error).
 
The RSA and PublicKey object within the Microsoft.WSDK.Security.Cryptography.X509Certificates can ExportParameters. But this is not new because both properties are RSA object (which could ExportParameters before WSDK). What's new is that the new X509Certificate class exports both RSA and PublicKey properties!
 
You can export the private key only if the private key is marked exportable (not the certificate). Certificates are public (so they're always "exportable").
GeneralRe: The X509Certificate class provides the function ExportParametersmemberManuel Permuy6 Oct '02 - 13:38 
Your're absolutly right. Thanks for writing again, it made me understand what you mean and also realize that I have to be more specific in writing.
 
I alredy submitted and update of the article, but in the next update I will correct the error in the article.
GeneralRe: The X509Certificate class provides the function ExportParameterssussAlex Butcher22 Dec '02 - 22:28 
I have imported a pfx file markign the public key as exportable, but calling .Key.ExpotParameters(true) throws an exception:
 
Key informatin could not be exported by the cryptograhpic service provider for this implementation.
 
If anyone has any suggestions I would be most grateful.
GeneralRe: The X509Certificate class provides the function ExportParametersmemberSteveC-A929 Jan '04 - 9:03 
A .pfx is not a true PKCS#12 implementation (it's a proprietary Microsoft variant), possibly that is what you are seeing.
Question"FCL"?sitebuilderUwe Keim25 Sep '02 - 20:59 
"Framework Component Library"?
"f***ing Cool Library"?
 
--
Scanned MSDN Mag ad with YOUR name: www.magerquark.de/misc/CodeProject.html
See me: www.magerquark.de
AnswerRe: "FCL"?sussAnonymous25 Sep '02 - 21:26 
Framework Class Library
AnswerRe: "FCL"?memberManuel Permuy27 Sep '02 - 5:52 
I think Microsofts did a pretty good job with the Framework Component Library and most of the time is't f***ing cool Wink | ;) but some parts of windows functionality (with all it's API and COM objects) are not (yet) part of it or ported badly (like the EventLog-Support).

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 10 Oct 2002
Article Copyright 2002 by Manuel Permuy
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid