Data security within the .NET framework

Lesson 1: Authenticating and authorising users



The two processes closely related and often confused.

WindowsIdentity class

Represents a windows user account. Provides access to user name, authentication type and account token. Does not allow authentication - windows has already done this, it simply stores the result of the authentication (including user name and authentication token). Call one of following methods to create instance:

Examination of object is useful if for example sections of code displays information that should only be available to authenticated users.

WindowsPrincipal class

Provides access to the groups a user belongs to.

Created by instance of WindowsIdentity class, e.g.

WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();

WindowsPincipal currentPrincipal = new WindowsPrincipal(currentIdentity);

Alternatively, can extract WindowsPrincipal from current thread, e.g.:


WindowsPrincipal currentPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;

To query for built in groups pass to the WindowsPrincipal.IsInRole method a member of the System.Security.Principal.WindowsBuiltInRole class (each member of this class representing a built in group).

To query for custom groups, pass a string value (in format DOMAIN\Group Name) to the overloaded IsInRole method.

PrincipalPermission Class

Enables you to check active principal for both declarative and imperative security actions. Used to decoratively demand that users running code have been authenticated or belong to specified role. By passing identity info (user name or role) to constructor the class can be used to demand that identity of actual principal match this information. Can set any combination of three properties:

Demand method verifies active principal meets requirements specified in properties.

Declarative Role Based Security to Restrict Method Access

Instructs runtime to perform checks before running method. Most secure way to restrict access to code as checks performed before code executed. Two primary disadvantages:

  1. Can only be used to restrict access to entire methods

May result in runtime throwing exception. If method was called by a windows event, this will catch the exception and application execution halts.

To use have three elements in code:

e.g. Following code calls method that is protected with a declarative RBS demand, displays a message box if user lacks necessary permission:



catch (System.Security.SecurityException)
MessageBox.Show("You lack permission.");

[PrincipalPermission(SecurityAction.Demand, Role=@"BUILTIN\Adminstrators")]
static void AdministratorsOnlyMethod()...

Can use multiple declarative demands to enable users who meet any of the demands to execute the code.

Imperative Role Based Security to Restrict Access To Parts of Methods

Declared within code. To use must have four elements:

Use one of three overloaded constructors:

Use Windows security policy


// Grant access to members of VS Developers group
PrincipalPermission p = new PrincipalPermission(null, System.Environment.MachineName + @"\VS Developers", true);



catch (System.Security.SecurityException)



Implement Custom Users and Roles

To authenticate against custom database use System.Security.PrincipalIIdentity and IPrincipal interfaces. Can extend interfaces with own classes adding customer properties and functionalities (e.g. customer address).

IIdentity is template for creating identity classes. WindowsIdentity is an example of an implementation, the bulk of its method and properties being inherited directly from IIdentity. FormsIdentity and PassportIdentity support web authentication whilst GenericIdentity provides a very flexible implementation. To implement must implement:

Class constructor should define each of objects properties

When NOT to implement IIdentity

If want to add properties to a windows logon whilst still using the Windows token or other Windows security properties then derive custom identity from WindowsIdentity. Same applies for IPrincipal and WindowsPrincipal.

Creating Custom Principal Class

Objects based on IPrincipal interface represent security context of user - includes identity and roles (or groups) they belong to. To implement must provide at least one constructor, one property and one method. Constructor takes IIdentity object and array of settings containing identity roles. Property implements IPrincipal.Identity and returns the principals identify object. The method is the boolean IPrincipal.IsInRole taking a string and role being queried and returns true if the identity is in the role.

Create Simple User Privilege Models

If don't want to use framework classes based on IIdentity and IPrincipal and need only basic functionality provided by these interfaces then use the GenericIdentity and GenericPrincipal classes. These classes only implement the methods required by the interfaces. GenericIdentity has two constructors, either username or username and authentication type. GenericPrincipal has a single constructor taking a GenericIdentity object and array of strings representing the roles.

GenericIdentity myUser = new GenericIDentity("TAdams", "SmartCard");

GenericPrincipal myPrincipal = new GenericPrincipal(myUser, new string[] {"IT", "Users"});


Demands with Custom Identities and Principals

Whether using custom or generic implementations of IIdentity and IPrincipal can take advantage of same declarative and imperative RBS techniques used for WindowsPrincipal and WindowsIdentity.


Authentication Exceptions in Streams

When authentication to remote computers using NegotiateStream or SslStream class the framework will throw exception if client or server can not be authenticated. Should always be prepared to catch the following:

Lesson 2: Access Controls Lists

Operating systems use ACLs to provide similar functionality to permission demands.

Discretionary Access Control List

A DACL is an authorisation restriction mechanism that identifies users and groups allowed or denied access to an object. If a DACL does not explicitly identify a user or any groups that user is a member of then the user is denied access to that object. A DACL contains access control entities (ACE) that determine user access to object. An ACE is an entry in the DACL that grants permission to a user or group.

To make managing permission efficient they support inheritance. When Windows first installed most objects only have inherited permissions. Inherited permissions propagate to an object form its parent.

Calculating Effective Permissions

To calculate effective permissions Windows must do more than just look up users name in ACL. ACEs can assign permissions to users or groups. Users can be members of multiple groups and groups can be nested within one another. Therefore a user can have several different ACEs in a DACL.

Granted permissions are cumulative, but ACEs that deny access always override ACEs that grant access.

ACEs in .NET Framework

Different resources have unique permissions that define an ACE, e.g. Both files and registry entries have Full Control and Delete permissions, Read & Execute is unique to files and Query Values is unique to the registry. Fortunately permissions for different resources function similarly so all classes inherit from common base classes.

To specify file and folder permissions use the FileSystemsRights enumeration.

Security Access Control List

A SACL is a usage logging mechanism that determines how file or folder access is audited. Unlike DACL cannot restrict access to object. A SACL causes an event to be recorded in the security event log when a user access the object. Used to troubleshoot problems and identify intrusions.

By default Windows does not log audit events. Must enable Audit Object Access security policy via the Local Security Policy MMC.

View and Configure ACLs within an Assembly

System.Security.AccessControl namespace contains variety of classes for viewing and accessing ACLs. For each resource type the namespace provides three classes:

Analyse ACLs

RegistrySecurity rs = Registry.LocalMachine.GetAccessControl();

AuthorizationRuleCollection arc = rs.GetAccessRules(true, true, type(NTAccount));

foreach(RegistryAccessRule ar in arc) Console.Writeline(ar.IdentityReference + ar.AccessControlType + ar.RegistryRights);

Configure ACLs

DirectorySecurity ds = Directory.GetAccessControl(dir);

ds.AddAccessRule(new FileSystemAccessRule("Guest", FileSystemRights.Read, AccessControlType.Allow));

Directory.SetAccessControl(dir, ds);

Lesson 3: Encryption and Decryption

Using Symmetric Keys

Also known as secret-key encryption. Relies on both parties knowing the key.

Algorithms (called cyphers) process plain text with encryption key to generate encrypted data (called the cypher text). The cypher text cannot be decrypted into plain text without knowing the secret key.

Symmetric cyphers are fast and suited to encrypting large amounts of data.

To identify the plain text an attacker need only use a brute force attack by trying every possible key combination. Typically this will take hundreds of years (if not longer).

Symmetric encryption presumes the two parties have agreed on a key. Agreeing on a key can be difficult as it cannot be encrypted, consequently a secure mechanism must exist for exchanging keys. Encryption keys should be changed regularly (for the same reasons as passwords should be changed).

Symmetric Algorithm Classes in the .Net Framework

Found in the System.Security.Cryptography namespace.

| ** Class ** | ** Key Length ** | ** Description ** | | RijndaelManaged | 128 - 256 bits (32 bit increments)| Also known as AES. Only framework class that is fully managed. Use in preference. | | RC2 | Variable | Designed to replace DES with variable key sizes | | DES | 56 bits | Short key length = easy to crack so should be avoided. Commonly used as compatible with wide range of legacy platforms. | | TripleDES | 156 bits (only 112 used) | Applies DES 3 times |

All derive from SymmetricAlgorithm base class and share following properties:

Establishing a Symmetric Key

Cannot use any piece of data as a key, must be of specific length.

To generate random key simply create instance of algorithm object. Can create another random key by calling the GenerateKey method on the object.

Can generate valid key from user supplied password via the Rfc2898DeriveBytes class. Class requires three values in addition to the password - a salt value, IV and number of iterations used to generate key. The password and these values must be common between both parties. These values can be passed in to the class constructor and are available via class properties.

String password = "[P@55w0r]()]";

RijndaelManaged myAlg = new RijndaelManaged();

byte[] salt = Encoding.ASCII.GetBytes("My SALT");

Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt);

myAlg.Key = key.GetBytes(myAlg.KeySize / 8);

myAlg.IV = key.GetBytes(myAlg.BlockSize / 8);

Encrypting / Decrypting Messages

Similar to reading and writing to files and streams.

Using Asymmetric Keys

Also known as public-key encryption.

Overcomes symmetric encryption significant disability - requiring both parties to know the key.

Relies on key pairs, public key that is freely distributed and private key used to decrypt cypher text encrypted with the private key.

Generally both client and server exchange public keys, but encryption is only required in one direction then only the peer receiving encrypted communications needs to supply a key.

Not as fast as symmetric algorithms and so unsuited to encrypting large amounts of data. One common use of asymmetric algorithm is to encrypt and transfer symmetric key and IV - this is technique used by HTTPS and SSL.

Asymmetric Algorithms in .NET

Two classes provided, both deriving from System.Security.Cryptography.AsymmetricAlgorithm. Has following properties (several similar to SymmetricAlgorithm):

The RSACryptoServiceProvider class also provides these properties:

The RSACryptoServiceProvider class also provides these methods:

Export / Import Asymmetric Keys and Key Pairs

Much more complex than symmetric keys. Key pair represented by RASParameters structure, significant members:

| ID | The private key | | Exponent | Also known as e, this is short part of public key | | Modulus | Also known as n, this is the long part of the public key. |

Need to export public key as without this no one can send encrypted messages to you. Only export private key if need to reuse later, if it is stored then the application must protect the privacy of the private key.

To store or transmit the exported key use RSACryptoServiceProvider.ToXmlString(). Like ExportParameters it takes a boolean indicating if private key should be exported.

Storing key pairs for later reuse

Can export keys to the cryptographic service provider (CSP) using CryptoAPI key storage.

Framework handles creating and retrieving keys. First time specify a CspParameters object and set PersistKetInCsp to true the framework will create key container and store key. When called subsequently the framework will detect that a key container for that name exists already and retrieve the stored private key.

Encrypt / Decrypt messages using asymmetric encryption

Both the encrypt and decrypt methods take two parameters

string msg - "Hello, world!";

RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider();

byte []msgBytes = Encoding.Unicode.GetBytes(msg);

byte []encryptedMsg = myRSA.Encrypt(msgBytes, true);

byte []decryptedBytes = myRsa.Decrypt(encryptedMsg, true);

string msg2 = Encoding.Unicode.GetString(decryptedBytes);

Validating Integrity With Hashes

Important use of cryptography is to protect data using hashes. A hash is a checksum unique to some data. Can use hash to verify that data has not been modified after hash generated.

Cannot derive original data from hash, even if original data is very small. Often used to verify passwords without storing password themselves.

Framework includes six non-keyed hash algorithms and two keyed algorithms.

Non-keyed hashing algorithms

| Abstract class | Implementation Class | Description | | MD5 | MD5CryptoServiceProvider | MD5 with hash size of 128 bits | | RIPEMD160 | RIPEMD160Managed | MD160 with hash size of 160 bits | | SHA1 | SHA1CryptoServiceProvider | SHA of 160 bits | | SHA256 | SHA256Managed SHA of 256 bits | | SHA384 | SHA384MAnaged | SHAof 384 bits | | SHA512 | SHA512Managed | SHA of 512 bits |

Keys have to be protected against modification - otherwise it defeats their value. The framework provides two classes that encrypt the key using a secret key known to both sender and receiver

| Class | Description | | HMACSHA1 | Hash based message authentication code. Used to determine if message sent over insecure channel has been tampered with. Accepts keys of any size and produces hash of 20 bytes | | MACTripleDES | Message authentication code using TripleDES. Accepts key length of 8, 16 or 24 bytes. Produces hash of 8 bytes. |

Compute non-keyed hash

// Create hash algorithm object

MD5 myHash = new MD5CryptoSevicePovider();

// Store data to be hashed in byte array

FileStream file = new FileStream(args[0], FileMode.Open, FileAccess.Read);

BinaryReader reader = new BinaryReader(file);

// Call HashAlgorithm.ComputeHash


// Retrieve the HashAlgorith.Hash byte array


Compute keyed hash

// Create secret key (shared by using the hash

byte[] salt = Encoding.ASCII.GetBytes("This is a salt");

Rfc2898DeriveBytes passwordKey = new Rfc2898DeriveBytes(args[0], salt);

byte[] secretKey = passwordKey.GetBytes(16);

// Create hash algorithm object

HMACSHA1 myHash = new HMACSHA1(secretKey);

// Store data to be hashed in byte array

FileStream file = new FileStream(args[0], FileMode.Open, FileAccess.Read);

BinaryReader reader = new BinaryReader(file);

// Call HashAlgorithm.ComputeHash


// Retrieve the HashAlgorith.Hash byte array


Signing Files

Digital signature is appended to electronic data to prove it was created by someone possessing a specific private key. The framework provides two classes for generating and verifying signatures - DSACryptoServiceProvider and SRACryptoServiceProvider. Both implement following methods:

Separate methods are provided to generate and verify signatures (unlike hash generation) as the signature is generated by an asymmetric algorithm, i.e. the recipient checking the signature only has access to the senders public key.

Signing and Verifying File

// Create digital signature algorithm object

DSACryptoServiceProvider signer = new DSACryptoServiceProvider();

// Store data to be signed in byte array

FileStream file = new FileStream(args[0], FileMode,Open, FileAccess.Read);

BinaryReader reader = new BinaryReader(file);

byte[] data = reader.GetBytes((int)file.Length);

// Generate signature

byte[] signature = signer.SignData(data);

// Export the key

string publicKey = signer.ToXmlString(false);


// Create digital signature algorithm object

DSACryptoServiceProvider verifier = new DSACryptoServiceProvider();

// Import public key


// Store data to be verified in byte array

FileStream file2 = new FileStream(args[0], FileMode,Open, FileAccess.Read);

BinaryReader reader2 = new BinaryReader(file2);

byte[] data2 = reader2.GetBytes((int)file2.Length);

// Verify the signature

if (!verifier.VerifyData(data2, signature)) Console.WriteLine("Error");