Why Coding Standards
Simple: maintainability. If, 6 months down the line, your customer isn't too happy with the product and wants an enhancement in the application you have created, you should be able to do it without introducing new bugs. There are a lot of other good reasons, but this is the one which concerns us more than anything else.
Not following any standard is like going with a temporary solution (which might lead to a permanent problem) and, as you will see, it takes less effort to keep in mind a few simple measures than to do haphazard coding.
All you have to do is study good standards once and keep them in the back of your head. Trust me; it's worth it.
Contents
1. Naming - What is meant by meaningful names
2. Casing - When to use PascalCase and when camelCase
4. Generics - Proper usage
5. Delegates - Proper usage
6. Miscellaneous - Some short tidbits
7. Common Pitfalls - Mistakes we should watch out for
8. References - Where to get more information
Naming
"The beginning of wisdom is to call things by their right names" - Chinese Proverb
"Meaningful" is the keyword in naming. By meaningful names, I mean concise names that accurately describe the variable, method or object. Let's see how this would be in C#:
Namespaces - Names should be meaningful and complete. Indicate your company or name, product and then your utility. Do not abbreviate.
//Good namespace CompanyName.ProductName.Utility //Bad namespace CN.PROD.UTIL
Classes - Class names should always be a noun and, again, should be meaningful. Avoid verbs
//Good class Image { ... } class Filters { ... } //Bad class Act { ... } class Enhance { ... }
Methods - Always use a verb-noun pair, unless the method operates on its containing class, in which case, use just a verb.
//Good public void InitializePath(); public void GetPath(); public void ShowChanges(); public void System.Windows.Forms.Form.Show(); //Bad public void Path(); public void Changes();
Methods with return values - The name should reflect the return value.
//Good public int GetImageWidth(Bitmap image); //Bad public int GetDimensions(Bitmap image);
Variables - Do not abbreviate variable names. Variable names should again be descriptive and meaningful.
//Good int customerCount = 0; int index = 0; string temp = ""; //Bad int cc = 0; int i = 0; string t = "";
Private member variables - Prefix class member variables withm_.
public class Image { private int m_initialWidth; private string m_filename; ... }
Interfaces - Prefix all interface names withI. Use a name that reflects an interface's capabilities, either a general noun or an "-able".
interface IClock { DateTime Time { get; set; } ... } interface IAlarmClock : IClock { void Ring(); DateTime AlarmTime { get; set; } ... } interface IDisposable { void Dispose(); } interface IEnumerable { IEnumerator GetEnumerator(); }
Custom attributes - Suffix all attribute class names withAttribute. The C# compiler recognizes this and allows you to omit it when using it.
public class IsTestedAttribute : Attribute { public override string ToString() { return "Is Tested"; } } //"Attribute" suffix can be omitted [IsTested] public void Ring();
Custom exceptions - Suffix all custom exception names withException.
public class UserNotExistentException : System.ApplicationException { ... }
Delegates - Suffix all event handlers withHandler; suffix everything else withDelegate.
public delegate void ImageChangedHandler(); public delegate string StringMethodDelegate();
Casing
C# standards dictate that you use a certain pattern of Pascal Casing (first word capitalized) and Camel Casing (all but first word capitalized).
Pascal Casing - use PascalCasing for classes, types, methods and constants.
public class ImageClass { const int MaxImageWidth = 100; public void ResizeImage(); } enum Days { Sunday, Monday, Tuesday, ... }
Camel Casing - use camelCasing for local variables and method arguments.
int ResizeImage(int imageCount) { for(int index = 0; index < imageCount; index++) { ... } }
Generics
Generics, introduced in .NET 2.0, are classes that work uniformly on values of different types.
Use capital letters for types; don't use "Type" as a suffix.
//Good public class Stack ‹T› //Bad public class Stack ‹t› public class Stack ‹Type›
Delegates
Use delegate inference instead of explicit delegate instantiation.
public delegate void ImageChangedDelegate(); public void ChangeImage() { ... } //Good ImageChangedDelegate imageChanged = ChangeImage; //Bad ImageChangedDelegate imageChanged = new ImageChangedDelegate(ChangeImage);
Use empty parenthesis on anonymous methods without parameters.
public delegate void ImageChangeDelegate(); ImageChangedDelegate imageChanged = delegate() { ... }
Miscellaneous
- Avoid putting
usingstatements inside a namespace
- Check spelling in comments
- Always start left curly brace { on a new line
- Group framework namespaces together; add custom and thirdparty namespaces below
- Use strict indentation (3 or 4 spaces, no tabs)
- Avoid fully qualified type names
- Indent comment at the same line as the code
- All member variables should be declared at the top of classes; properties and methods should be separated by one line each
- Declare local variables as close as possible to the first time they're used
- File names should reflect the classes that they contain
Common Pitfalls
Let's face it, we all do these things one time or another. Let's avoid them as best as we can:
Names that make sense to no one but ourselves.
string myVar; MyFunction();
Single or double letter variable names (this is excusable for local variables).
int a, b, c, a1, j1, i, j, k, ii, jj, kk, etc.
Abstract names.
private void DoThis(); Routine48(); string ZimboVariable;
Acronyms.
//AcronymFunction AF(); //SuperFastAcronymFunction SFAT()
Different functions with similar names.
DoThis(); DoThisWillYa();
Names starting with underscores. They look cool, but let's not ;)
int _m1 = 0; string __m2 = ""; string _TempVariable = "";
Variable names with subtle and context-less meanings.
string asterix = ""; // (this is the best function of all) void God() { ... }
Abbreviations.
string num; int abr; int i;
Serial Port Communication in C#
The serial port is a serial communication interface through which information transfers in or out one bit at a time.
A quick search on Google reveals that there are a lot of free serial port monitor applications available for PC users. However, what these applications lack, is the possibility of controlling the serial port in a direct manner. They are generally good “sniffers” but they do not allow the user to actually write to the serial port or control any device attached to it. The applications with the write capability encapsulated are not for free, and the cheapest costs about 50 Euro – a great deal of money taking into account how easy it is to make a personalized application.
This article will show how it is possible to build such an application using the C# environment. It is not intended to be a C# tutorial, but to teach a user who has basic knowledge of C or C# to integrate serial port control in one of his applications.
For the example application, I have used the SharpDevelop development environment which includes a C# compiler. This is an open source IDE which takes up very little space on your hard drive and can be a good alternative to users who do not want to install the gigabytes of Visual Studio on their PCs for a simple serial port application.
Once you have downloaded and installed the SharpDevelop environment, create a Windows Application project (solution) called SerialPort:
Once you have created the application, display the windows form that was automatically created (by clicking on the “Design” button at the bottom of the screen) and unroll the menu available under “Components” available on the left-hand menu:
You will notice that one of the components available here is the one called “SerialPort”. Pick that component and drag&drop it over the surface of the form on the right. This will add the component to your project. The object that is created is called “serialPort1” and it will be used to access the serial port. To be able to use this component, however, you need to add at the beginning of your code the directive for using the System.IO.Ports namespace, as this is not added by default when you create the solution:
using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.IO.Ports;
In this function we will perform several tasks. The first one is to configure the baud rate, COM port, number of data bits, parity and stop bits of the communication:
//configuring the serial port serialPort1.PortName="COM1"; serialPort1.BaudRate=9600; serialPort1.DataBits=8; serialPort1.Parity=Parity.None; serialPort1.StopBits= StopBits.One;
//opening the serial port serialPort1.Open();
OK, it is now time to write to the serial port:
//write data to serial port
serialPort1.Write("ABC");Once the write operation is performed, you must not forget to close the port:
//close the port serialPort1.Close();
void Button1Click(object sender, EventArgs e)
{
//configuring the serial port
serialPort1.PortName="COM1";
serialPort1.BaudRate=9600;
serialPort1.DataBits=8;
serialPort1.Parity=Parity.None;
serialPort1.StopBits= StopBits.One;
//opening the serial port
serialPort1.Open();
//write data to serial port
serialPort1.Write("ABC");
//close the port
serialPort1.Close();
}Launch Visual Studio from the Command Prompt
If you want to exercise obsessive control about how Visual Studio is launched, you’ll be pleased to know that you can do it all from your friendly neighborhood command prompt.
The Visual Studio IDE executable is called devenv.exe and includes a number of command-line switches that can be very useful. Elsewhere in this book, we have looked at a couple of these switches, but in this hack, you will learn about all the switches and how they can be used.
Typing command-line switches every time you launch an application is time consuming and just plain inefficient. Remember that you can create shortcuts that call an executable using command-line switches; you could have a number of different shortcuts for Visual Studio with different command-line switches.
Setting Fonts
One of the simplest, but very useful, things you can accomplish using command- line switches is setting the font and font size for the IDE. To specify the font, you can use the/fn switch, and to specify the size, you use /fs. It is important to note that this is not the font size of the text or contents of your files, but rather the text size of the IDE. You won’t see it affect the normal menus, but the font and size of the document tabs, options dialog, and so forth will all be in the specified font type and size. The following command line could be used to set the Visual Studio IDE font to Verdana and the size to 14:
C:\> devenv /fn Verdana /fs 14 This does not need to be set each and every time you run the IDE; these settings will be saved and used from here on out. This is the same setting you can configure under Tools -> Options -> Fonts and Colors, then selecting the Dialogs and Tool Windows option from the Show Settings drop-down.
Execute a Command
Using the command switch, you can launch Visual Studio and automatically call a Visual Studio command. All you need to do is specify the switch /command and then follow it with the name of the command that you want to execute. In this example, I will call theFile.OpenSolution command—I almost always open Visual Studio with the intent of opening a solution, so this saves a couple of mouse clicks: C:\> devenv /command File.OpenSolution When you run this command, Visual Studio will open, and the New Solution dialog will open. You could also use /command to execute a macro you have written to perform more complex actions.
Run a Solution
You can automatically run a solution from the command line using the/run switch. The following is an example of running a solution from the command line: C:\> devenv /run HacksWinSample.sln When this command is run, the IDE will open and automatically jump into debug mode loading your application. You can also use the
/runexit switch, which will launch your applications and minimize the IDE. When you close your application, the IDE will be closed as well. Building Projects and Solutions
You can build your projects or solutions using command-line switches. This can be a great alternative if you don’t have time to configure a build tool like NAnt, but want to create a build process using a batch file. To build a solution, you use the/build switch as well as the /project or /solution switch. Here is an example of building a solution from the command line: C:\> devenv HacksWinSample.sln /build release After the
/build switch, you specify the solution configuration that you want to use when building this solution—in this example, I have used the release configuration. Running this will build the solution without opening the IDE, and the build results will be returned to the command prompt window. A number of other build switches are detailed in Table 10-1. Table 10-1. Build switches
| Switch | Description |
/clean | Cleans the project or solution according to the configuration of that project or solution |
/rebuild | Cleans and builds the project or solution |
/project | Specifies the project to build |
/projectconfig | Specifies the configuration to use when building the project |
/deploy | Tells Visual Studio to deploy the solution after it has been built |
Other Switches
A number of other command-line switches can be used to do various things with Visual Studio. These command-line switches are shown in Table 10-2./out Specifies the name of a file to send any build errors to Table 10-2. Command-line switches
| Switch | Description |
/lcid | Specifies the default language to use for the IDE. Example: devenv |
/lcid | 1033 |
/mdi | Specifies that Visual Studio should be run in MDI mode. |
/mditabs | Specifies that Visual Studio should be run in MDI mode with tabs on documents enabled. |
/migratesettings | Tells Visual Studio to trigger the settings migration process, which can be used to move settings from one version of Visual Studio to another. (You usually see this screen the first time you run a new installation of Visual Studio.) |
/nologo | Launches Visual Studio without the splash screen. |
/noVSIP | Disables a developer’s VSIP license on this workstation. |
/safemode | Specifies that Visual Studio should open without loading any VSIP packages. |
/setup | Resets certain parts of Visual Studio. |
/resetskippkgs | Enables VSIP packages by clearing any SkipLoading tags. After running safe mode, this will need to be run to reenable any packages you still want to run. |
/rootsuffix | Can be used to specify a registry suffix. |
/? | You can always use this switch to view the help for devenv.exe. |
Exchange Data More Securely with XML Signatures and Encryption
A simple document:
<docRoot> <a>Hello</a> <b>World</b> </docRoot>
<docRoot>
<a>Hello</a>
<b>World</b>
<Signature xmlns="http://www.w3c.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3c.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform
Algorithm=
"http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#sha1"/>
<DigestValue>cbPT0951Ghb2G3UjpVjWw+7q0Bc=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IoEwS(3 lines of Base64 text)XSo=</SignatureValue>
</Signature>
</docRoot>- Apply each transform algorithm specified in the Transform elements to the data for the Reference, in the order the transforms appear under the Transforms element.
- Hash the transformed data using the hashing algorithm specified by the DigestMethod element of the Reference.
- Store the resulting hash value in the DigestValue element of the Reference.
- Apply each transform algorithm specified in the Transform elements of the Reference to the data for the Reference, in the order the transforms appear under the Transforms element.
- Hash the transformed data for the reference using the hashing algorithm that is specified by the DigestMethod element of the reference.
- Compare the hash value computed with the value stored in the DigestValue element.
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
// Also, add a reference to System.Security.dll
// Load the signed data
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load("data-signed.xml");
// Find the Signature element in the document
XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
XmlElement sigElt = (XmlElement)doc.SelectSingleNode(
"//dsig:Signature", nsm);
// Load the signature for verification
SignedXml sig = new SignedXml(doc);
sig.LoadXml(sigElt);
// Verify the signature, assume the public key part of the
// signing key is in the key variable
if (sig.CheckSignature(key))
Console.WriteLine("Signature verified");
else
Console.WriteLine("Signature not valid");using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
// Also, add a reference to System.Security.dll
// Assume the data to sign is in the data.xml file, load it, and
// set up the signature object.
XmlDocument doc = new XmlDocument();
doc.Load("data.xml");
SignedXml sig = new SignedXml(doc);
// Make a random RSA key, and set it on the signature for signing.
RSA key = new RSACryptoServiceProvider();
sig.SigningKey = key;
// Create a Reference to the containing document, add the enveloped
// transform, and then add the Reference to the signature
Reference refr = new Reference("");
refr.AddTransform(new XmlDsigEnvelopedSignatureTransform());
sig.AddReference(refr);
// Compute the signature, add it to the XML document, and save
sig.ComputeSignature();
doc.DocumentElement.AppendChild(sig.GetXml());
doc.Save("data-signed.xml");<Reference URI="http://www.example.com/foo.jpg">
<DigestMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#sha1" />
<DigestValue>cbPT0951Ghb2G3UjpVjWw+7q0Bc=</DigestValue>
</Reference>// Create a Reference to detached data, assume a SignedXml object in sig
Reference refr = new Reference("http://www.example.com/foo.jpg");
sig.AddReference(refr);<Reference URI="#myData">
<DigestMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#sha1" />
<DigestValue>cbPT0951Ghb2G3UjpVjWw+7q0Bc=</DigestValue>
</Reference><Object Id="myData">Your XML goes here</Object>
// Create a Reference to XML data in the containing document,
// assume a SignedXml object in sig
Reference refr = new Reference("#myData");
sig.AddReference(refr);// Adds a DataObject with an Id of "#myData" to the signature, assume a // SignedXml object in sig, and xml data of type XmlNodeList in data DataObject dobj = new DataObject(); dobj.Id = "myData"; // Note: no # dobj.Data = data; // XML Data of the Object sig.AddObject(dobj);
- Any canonicalization algorithm can be used as a transform.
- The Base64 transform allows you to decode data in the Base64 encoding.
- The XSLT transform allows you to apply an XSLT stylesheet to XML data before signing it. The XSLT stylesheet to be applied is specified as XML under the Transform element.
- The XPath transform allows you to filter XML data with an XPath expression.
<a> <b>Some data</b> <c>More data</c> </a> <d> <b>Even more data</b> </d>
<b>Some data</b> <b>Even more data</b>
<Transform Algorithm="http://www.w3c.org/TR/1999/REC-xpath-19991116"> <XPath>ancestor-or-self::b</XPath> </Transform>
// Add an XPath transform to a reference.
// Assume a Reference object in refr
XmlDocument doc = new XmlDocument();
doc.LoadXml("<XPath>ancestor-or-self::b</XPath>");
XmlDsigXPathTransform xptrans = new XmlDsigXPathTransform();
xptrans.LoadInnerXml(doc.ChildNodes);
refr.AddTransform(xptrans);<root> <a >Some text</a> <b attr1="yes" attr2="no"></b> <c Id="foo">More text</c> </root> <root> <a>Some text</a> <b attr2="no" attr1="yes" /> <c Id="foo">More text</c> </root>
// Adds an KeyInfo element with RSA public key information to the // signature. // Assumes a SignedXml object in sig, and an RSA object in key. KeyInfo ki = new KeyInfo(); ki.AddClause(new RSAKeyValue(key)); sig.KeyInfo = ki;
<KeyInfo><KeyValue><RSAKeyValue> <Modulus>4LfG(2 lines of Base64 text)2Fr=</Modulus> <Exponent>AQAB</Exponent> </RSAKeyValue></KeyValue></KeyInfo>
// Verify a signature that includes RSAKeyInfo or DSAKeyInfo. // Assume a SignedXml object in sig. bool verified = sig.CheckSignature();
<docRoot>
<a>Hello</a>
<b>World</b>
<Signature xmlns="http://www.w3c.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3c.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform
Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-
signature"/>
<Transform
Algorithm="http://www.w3c.org/TR/1999/REC-xpath-19991116">
<XPath>ancestor-or-self::a</XPath>
</Transform>
</Transforms>
<DigestMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#sha1"/>
<DigestValue>mN4R0653F4ethOiTBeAu+7q0Be=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>X4Ie(3 lines of Base64 text)nP3=</SignatureValue>
</Signature>
</docRoot>// This method checks the signature profile for the signature
// in the supplied document. It ensures there is only one
// Signature element and only one enveloped reference with only
// one enveloped signature transform
public bool CheckSignatureProfile(XmlDocument doc)
{
// Make sure there is only one Signature element
XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
XmlNodeList sigList = doc.SelectNodes("//dsig:Signature", nsm);
if (sigList.Count > 1)
return false; //Wrong number of Signature elements
//Make sure the Signature element has only one Reference
XmlElement sigElt = (XmlElement)sigList[0];
XmlNodeList refList = sigElt.SelectNodes(
"dsig:SignedInfo/dsig:Reference", nsm);
if (refList.Count > 1)
return false; //Wrong number of Reference elements
// Make sure the Reference URI is ""
XmlElement refElt = (XmlElement)refList[0];
XmlAttributeCollection refAttrs = refElt.Attributes;
XmlNode uriAttr = refAttrs.GetNamedItem("URI");
if ((uriAttr == null) || (uriAttr.Value != ""))
return false; // Wrong type of reference
// Make sure the only tranform is the enveloped signature transform
XmlNodeList transList = refElt.SelectNodes(
"dsig:Transforms/dsig:Transform", nsm);
if (transList.Count != 1)
return false; //Wrong number of Transform elements
XmlElement transElt = (XmlElement)transList[0];
string transAlg = transElt.GetAttribute("Algorithm");
if (transAlg != SignedXml.XmlDsigEnvelopedSignatureTransformUrl)
return false; //Wrong type of transform
return true;
}<root>
<myData1>Some Data</myData1>
<myData2>More data</myData2>
<Signature xmlns="http://www.w3c.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3c.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform
Algorithm=
"http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#sha1"/>
<DigestValue>cbPT0951Ghb2G3UjpVjWw+7q0Bc=</DigestValue>
</Reference>
<Reference URI="#signer">
<Transforms>
<Transform
Algorithm=
"http://www.w3c.org/TR/1999/REC-xpath-19991116">
<XPath xmlns:my="http://example">
ancestor-or-self::my:SignerID
</XPath>
</Transform>
</Transforms>
<DigestMethod
Algorithm="http://www.w3c.org/2000/09/xmldsig#sha1"/>
<DigestValue>mN4R0653F4ethOiTBeAu+7q0Be</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IoEwS...</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>4LfG(2 lines of Base64 text)2Fr=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
<Object Id="signer">
<my:SignerData xmlns:my="http://example">
<my:SignerName>Mike</my:SignerName>
<my:SignerID>4815</my:SignerID>
</my:SignerData>
</Object>
</Signature>
</root>A simple document:
<docRoot> <a>Hello</a> <b>World</b> </docRoot>
<docRoot>
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>recipient_public_key</KeyName>
</KeyInfo>
<CipherData>
<CipherValue>PrI6(3 lines of Base64 text)Dwy4=</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>awcH(3 lines of Base64 text)NNqQ=</CipherValue>
</CipherData>
</EncryptedData>
</docRoot>| URI Properties of EncryptedXml Class | Encrypting Data | Encrypting Keys | |
|---|---|---|---|
| AES | XmlEncAES256Url | | |
| XmlEncAES256KeyWrapUrl | | ||
| DES | XmlEncDESUrl | | |
| TripleDES | XmlEncTripleDESUrl | | |
| XmlEncTripleDESKeyWrapUrl | | ||
| RSA | XmlEncRSA1_5Url | |
| CipherReference Location | URI Format | Cipher Text Format |
|---|---|---|
| Same document | #order | Base64 string |
| Remote Web site | http://www.example.com/order.bin | Binary |
// Create evidence based on the referring document
Evidence evidence = new Evidence();
evidence.AddHost(new Zone(SecurityZone.Internet));
evidence.AddHost(new Site("untrustedsite"));
evidence.AddHost(new Url("untrustedsite/encrypted.xml"));
EncryptedXml exml = new EncryptedXml(untrustedDoc, evidence);<order>
<purchase>
<item quantity="1">Def Leppard: Pyromania</item>
<item quantity="1">Ozzy Osbourne: Goodbye to Romance</item>
</purchase>
<shipping>
<to>Shawn Farkas</to>
<street>One Microsoft Way</street>
<zip>98052</zip>
</shipping>
<payment>
<card type="visa">0000-0000-0000-0000</card>
</payment>
</order>// Assumes the order is in the order.xml file.
XmlDocument doc = new XmlDocument();
doc.Load("order.xml");
EncryptedXml exml = new EncryptedXml(doc);
// Set up the key mapping. Assumes a method called GetBillingKey
// that returns the RSA key for the billing department.
RSA billingKey = GetBillingKey();
exml.AddKeyNameMapping("billing", billingKey);// Find the element to encrypt.
XmlElement paymentElement =
doc.SelectSingleNode("//order/payment") as XmlElement;
// Encrypt the payment element, passing in the key name.
EncryptedData encryptedPayment =
exml.Encrypt(paymentElement, "billing");
// Swap the encrypted element for the unencrypted element.
EncryptedXml.ReplaceElement(paymentElement, encryptedPayment, true);<order>
<purchase>
<item quantity="1">Def Leppard: Pyromania</item>
<item quantity="1">Ozzy Osbourne: Goodbye to Romance</item>
</purchase>
<shipping>
<to>Shawn Farkas</to>
<street>One Microsoft Way</street>
<zip>98052</zip>
</shipping>
<payment>
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/
xmlenc#aes256-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/
xmlenc#kw-aes256" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>billing</KeyName>
</KeyInfo>
<CipherData>
<CipherValue>Sce6lLD+u2f8HzPFyuGxTF32z4mb2ugql3JuJIPAqIP98iYs+Muhqg==
</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>FXKC(3 lines of Base64 text)ApqQt</CipherValue>
</CipherData>
</EncryptedData>
</payment>
</order>// Assumes the encrypted order is in encrypted.xml
XmlDocument doc = new XmlDocument("encrypted.xml");
EncryptedXml exml = new EncryptedXml(doc, documentEvidence);// Set up the key mapping. Assumes a method called GetBillingKey
// that returns the RSA key for the billing department.
RSA billingKey = GetBillingKey();
exml.AddKeyNameMapping("billing", billingKey);// Decrypt the encrypted XML in the document exml.DecryptDocument();
// Use the private key from the certificate. Assumes a SignedXml // object in sig and an X509CertificateEx object in cert. sig.SigningKey = cert.PrivateKey;
// Add X.509 certificate info to the KeyInfo element. Assumes a // SignedXml object in sig and an X509CertificateEx in cert. KeyInfoX509Data keyInfoX509 = new KeyInfoX509Data(cert, X509IncludeOption.EndCertOnly); sig.KeyInfo.AddClause(keyInfoX509);
// Check the signature against the cert and verify the cert. Assumes a // SignedXml object in sig and an X509CertificateEx object in cert. bool verified = sig.CheckSignature(cert, true);
| Class | Description |
|---|---|
| XmlDecryptionTransform | Decrypts encrypted XML |
| XmlDsigBase64Transform | Decodes base64 encoded data |
| XmlDsigC14NTransform | Performs C14N canonicalization (see http://www.w3.org/TR/xml-c14n for more information) |
| XmlDsigEnvelopedSignatureTransform | Removes an enveloped signature from a document |
| XmlDsigExcC14NTransform | Performs exclusive C14N canonicalization (see http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718 for more information) |
| XmlDsigXPathTransform | Applies an XPath filter to the input XML |
| XmlDsigXsltTransform | Applies an XSLT transform to the input XML |
| XmlLicenseTransform | Implements the LTA transform |
| XmlDsigC14NWithCommentsTransform | Performs C14N canonicalization, but leaves comments in the canonicalized XML |
| XmlDsigExcC14NWithCommentsTransform | Performs exclusive C14N canonicalization, but leaves comments in the canonicalized XML |