.NET

in

Samples

 

Jan Šeda

jan.seda@skilldrive.com


1.  Foreword

Learning and using technologies is sometimes very boring and reading books takes too much time. Many developers use MSDN but there is a big issue - that there are too many articles and other sources that this huge quantity is not possible to absorb and confusing (maybe this is the reason why Russian search engine started a special indexer on MSDN itself, see http://msdn.rambler.ru). This is the reason why I don’t like reading technical books or MSDN articles like they would be bestsellers and searching on MSDN is terrifying experience at least for me).

That is why in December 2003 I have decided to write my own book (just for personal usage) with samples, descriptions and explanation of technologies – just short samples and many images where principles could be seen immediately so learning curve could be as short as possible. Later I’ve provided this book to my friends and they told me that it can be useful for other developers who want to learn fast and see results in a very short time.

 

So far I have been writing samples on „as-needed“ basis, many chapters are unfinished and cover specific topic just basically. Also my English translation has not being checked by a professional translator and I want to excuse myself for not being able to write perfect English expressions but I hope this book will be helpful to developers.


2.  Terms of Use

© 2004-2005 by Jan Šeda, Skilldrive

All rights reserved. Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, people and events depicted herein are fictitious and no association with any real company, organization, product, person or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of the author.

The information in this book is distributed on an “as is” basis, without warranty. While every precaution has been taken in the preparation of this book, the author shall not have any liability to any person or entitle with respect to any liability, loss or damage caused or alleged to be caused directly or indirectly by instructions contained in this book or by the computer software or hardware products described herein.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does o

Active Directory, ActiveX, Authenticode, BizTalk, DirectX, IntelliSense, JScript, Microsoft, MSDN, Visual Basic, Visual C++, Visual J++, Visual SourceSafe, Visual Studio, Windows, Windows Media, Windows NT and Windows Server are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

All other product names and company names mentioned herein are the property of their respective owners.


Contents

1.      Foreword. 2

2.      Terms of Use. 3

3.      Windows Security. 12

3.1. Basic terms. 12

3.1.1. Principal 12

3.1.2. Authority. 12

3.1.3. Authentication. 12

3.1.4. Authorization. 12

3.1.5. Trust 13

3.1.6. Logon Session. 14

3.1.7. Token. 15

3.1.8. Get SID for current identity. 17

3.1.9. Get object name for SID.. 19

3.2. Protecting system resources. 21

3.2.1. Test yourself on security & protection of system resources. 21

3.2.2. Rules behind propagation of rights on objects. 22

3.2.3. Get ACLs/ACEs for a file. 23

3.2.4. Set DACL for a file. 24

4.      Security Ratings. 25

4.1.1. What is a Common Criteria?. 26

4.1.2. Why is Common Criteria important?. 26

5.      Security Concepts in .NET environment 26

5.1. Basic layout of .NET Framework – Security parts. 26

5.2. Assembly. 27

5.2.1. Runtime security policy. 28

5.2.2. Types of security context for assemblies. 31

5.2.3. Generate key pair with sn.exe tool 32

5.2.4. Give an assembly a strong name. 32

5.2.5. Delayed signing of assembly. 32

5.2.6. List of permissions in policy levels. 33

5.2.7. List of permissions assign to current assembly. 34

5.2.8. Get permission list for a custom evidence. 35

5.2.9. List of declarative permissions of assembly. 36

5.2.10. Output assembly evidence list to XML file. 36

5.2.11. List policy levels and code groups where current assembly belongs. 37

5.3. Type safety, metadata and code verification. 38

5.3.1. Get info about types in assembly. 40

5.4. Application domains. 42

5.4.1. Application domain boundaries and objects. 42

5.4.2. Create application domain programmatically. 44

5.4.3. Shadow copy enabled for application domain. 45

5.5. Security tools available in .NET.. 45

5.6. Code Access Security. 47

5.6.1. Stack-walk. 47

5.6.2. Limit access permissions for a method. 49

5.6.3. Add new code group to runtime security. 50

5.7. Role-based Security. 51

5.7.1. Identity classes (also Whidbey) 51

5.7.2. Principal policy. 51

5.7.3. Principal classes. 54

5.7.4. Using GenericPrincipal class. 54

5.7.5. Get list of groups for current thread’s identity. 55

5.7.6. Get current user name. 56

5.7.7. Impersonate as another user 56

5.7.8. Declarative principal permissions for Windows roles. 58

5.7.9. Declarative principal permissions for custom roles. 59

5.7.10. List running processes and user accounts. 59

6.      Cryptography & Security. 61

6.1. Buffer Overrun. 61

6.1.1. CodeRed Worm, Buffer Overrun attack. 62

6.1.2. SQLSlammer 63

6.2. Algorithms for Encryption. 63

6.2.1. Well Known Algorithms for Symmetric Encryption. 63

6.2.2. Well Known Algorithms for Asymmetric Encryption. 63

6.2.3. Well Known Hash Algorithms. 64

6.3. Digital Certificates. 64

6.4. Secure Communication Standards. 64

6.4.1. IPSec (Internet Protocol Security) 64

6.4.2. Kerberos. 64

6.4.3. SSL (Secure Socket Layer) 64

7.      Cryptography. 68

7.1. Basic terms in cryptography. 68

7.2. A little bit of history. 69

7.2.1. Caesar cipher 69

7.2.2. Progress in cryptography. 71

7.3. PKCS. 72

7.4. CMV (Cryptographic Module validation) 73

7.4.1. Microsoft FIPS 140 certification. 74

7.4.2. .NET classes and FIPS 140. 74

7.5. Cryptography in .NET.. 74

7.6. Configuring .NET cryptography. 75

7.7. Win32 Security API and .NET.. 75

7.8. Random number generators. 76

7.8.1. Generating random values. 76

7.8.2. Generating random nonzero values. 76

7.8.3. Random number generator and other CSPs (Cryptographic Service Provider) 76

7.9. Hashing algorithms. 77

7.10. Symmetric encryption. 78

7.10.1. Block ciphers. 79

7.10.2. Stream ciphers. 79

7.10.3. Key distribution problem.. 80

7.10.4. Data Encryption Standard (DES) 80

7.10.5. Blowfish. 86

7.10.6. Twofish. 86

7.10.7. MARS. 86

7.10.8. Rijndael 87

7.10.9. Ronald Rivest’s (RC) ciphers. 87

7.10.10. Hash value using MD5 and SHA.. 87

7.10.11. Collision in MD5 algorithm.. 88

7.10.12. Classes for symmetric algorithms in .NET.. 90

7.10.13. Deriving symmetric keys from passwords. 90

7.10.14. Creating symmetric encryption classes. 91

7.10.15. Symmetric encryption/decryption of plaintext using DES. 92

7.10.16. Symmetric encryption/decryption of plaintext using RC2. 93

7.10.17. Symmetric encryption/decryption of plaintext using Rijndael 93

7.10.18. Determining weak and semi-weak keys in DES. 94

7.10.19. Deriving symmetric key from password using PBKDF1. 95

7.10.20. Deriving symmetric key & IV from a password using PBKDF1. 95

7.10.21. Deriving symmetric key from a password using PBKDF2. 96

7.10.22. Check valid key size for symmetric encryption. 96

7.10.23. Hybrid usage of symmetric and asymmetric encryption. 97

7.10.24. Hashing of plaintext and encryption/decryption using DES. 98

7.10.25. Keyed hash algorithm HMACSHA1. 99

7.10.26. Keyed hash algorithm MACTripleDES. 100

7.11. Asymmetric encryption. 100

7.11.1. Certificates & Certification authorities. 100

7.12. Assymetric encryption. 101

7.12.1. Classes for asymmetric algorithms in .NET.. 102

7.12.2. Storing public and private RSA keys in XML file. 102

7.12.3. Storing keys by CSP (Crypto Service Provider) 102

7.12.4. Encryption of plaintext using RSA with XML-stored key. 103

7.12.5. Encryption/decryption of plaintext using RSA.. 103

7.12.6. Encryption/decryption of plaintext using RSA with XML-stored key. 104

7.12.7. Encryption of plaintext using RSAParameters. 105

7.12.8. Encryption/Decryption of plaintext by RSA.. 106

7.12.9. Encryption with public key (exception) 106

7.12.10. How to encrypt/decrypt large data using RSA?. 107

7.12.11. Calling RSA/DSA from a Web service, ASP or COM+. 107

7.13. Digital signatures. 108

7.13.1. Sign and verify data with RSA I 108

7.13.2. Sign and verify data with RSA II 110

7.13.3. Sign and verify data with RSA using SignatureFormatter 110

7.13.4. Sign and verify data with DSA.. 111

7.14. Key exchange methods and classes. 112

7.14.1. Exchange symmetric key between two clients using OAEP. 112

7.15. Certificates. 114

7.15.1. Create X509Certificate from file generated by makecert.exe. 114

7.15.2. Create X.509 certificate from base64 encoded certificates. 114

7.15.3. Source library with CryptoAPI certificate mappings. 115

7.15.4. List of installed client’s certificates. 115

7.15.5. List of installed intermediate certification authorities. 116

7.15.6. List of installed root certificate authorities. 116

7.16. Data Protection API 116

7.17. Basic principles of DPAPI 118

7.17.1. User’s profile. 120

7.17.2. Source library with DPAPI methods. 121

7.17.3. Use DPAPI to encipher application data into file. 127

7.17.4. Use DPAPI to decipher application data from file. 127

7.17.5. DPAPI used to encrypt data in file in isolated storage. 128

7.17.6. DPAPI used to decrypt data from file in isolated storage. 129

7.17.7. Encrypt/Decrypt database connection string using DPAPI 130

7.17.8. Issues with user’s store and web services and COM+. 131

7.17.9. Managed DPAPI 131

7.18. XML Signatures. 132

7.18.1. Sign XML. 132

7.19. Isolated storage. 132

7.19.1. Storeadm.exe – administration of isolated storage in .NET.. 134

7.19.2. Opening of isolated storages for current user and domain. 135

7.19.3. Store data in file in isolated storage. 136

8.      Network Operations. 137

8.1.1. Retrieve DNS computer name. 137

8.1.2. Retrieve NetBIOS computer name. 137

8.1.3. Obtain IP address and host 137

8.1.4. Send email in .NET environment 137

8.1.5. Getting online stock information. 138

8.1.6. Retrieve email from POP3 mail server 139

9.      File operations. 140

9.1. General IO operations. 140

9.1.1. Get executing application’s path with reflection. 140

9.1.2. Get executing application’s path. 140

9.1.3. Classes working with file and directory information. 141

9.1.4. Change file & folder attributes. 141

9.1.5. Recursive list of directories/subdirectories & files. 142

9.2. Reading and writing from/to files. 142

9.2.1. BufferedStream.. 143

9.2.2. Read from file using BufferedStream.. 143

9.2.3. Read text from file. 144

9.2.4. Write text to file. 144

9.2.5. Create file and write to it 144

9.2.6. Append text to file. 145

9.2.7. Read from binary file. 145

9.2.8. Write to binary file. 146

9.2.9. Watch file system for changes. 146

10.        Text Manipulation & Internationalization. 147

10.1. String operations. 147

10.1.1. Append string. 147

10.1.2. Inserting/Removing string. 148

10.1.3. Replace string. 148

10.1.4. Reverse string. 148

10.1.5. Reverse string using recursion. 149

10.2. Formatting numbers. 149

10.2.1. Table with number formatting options. 149

10.2.2. Formatting of numeric values to currency. 150

10.2.3. Formatting of numeric values to currency with NumberFormatInfo. 150

10.2.4. Formatting of floating point values to a scientific notation (exponential) 151

10.2.5. Formatting of floating point values to specific number of decimals (fixed-point) 151

10.2.6. Formatting of numeric value to local culture specific number 151

10.2.7. Formatting of floating point value to roundtrip (can be converted back to number) 151

10.2.8. Formatting of an integer value to a hexadecimal number 152

10.2.9. Formatting floating point values to a percentage. 152

10.2.10. Formatting floating point values to a percentage with limited number of decimals. 152

10.2.11. Formatting of floating point values to a percentage with NumberFormatInfo. 152

10.3. Formatting date and time. 153

10.3.1. Table with date&time formatting options. 153

10.3.2. Formatting DateTime to the short date&time pattern (dddd, MMMM dd, yyyy, hh:mm) 154

10.3.3. Formatting DateTime to the full date&time pattern (dddd, MMMM dd, yyyy hh:mm:ss) 154

10.3.4. Formating DateTime to the short date numerical pattern (M/d/yyyy) 154

10.3.5. Formatting DateTime to the full date numerical pattern (dddd, MMMM dd, yyyy) 154

10.3.6. Formatting DateTime to the short date&time numerical pattern (M/d/yyyy hh:mm) 154

10.3.7. Formatting DateTime to the full date&time numerical pattern (M/d/yyyy hh:mm:ss) 155

10.3.8. Formatting DateTime to the month name pattern (MMMM dd) 155

10.3.9. Formatting DateTime to the short date pattern (MMMM, yyyy) 155

10.3.10. Formatting DateTime to the long time pattern (hh:mm:ss) 155

10.3.11. Formatting DateTime to the short time pattern (hh:mm) 155

10.3.12. Formatting DateTime to the RFC1123 pattern (ddd, dd MMM yyyy HH':'mm':'ss 'GMT') 156

10.3.13. Formatting DateTime to sortable pattern. 156

10.3.14. Formatting DateTime to universal sortable pattern (yyyy'-'MM'-'dd HH':'mm':'ss'Z') 156

10.3.15. Formatting DateTime to full date&time using universal time. 156

10.3.16. Formatting DateTime to custom format using DateTimeFormatInfo. 156

10.4. Custom number formatting. 157

10.4.1. Formatting of number to specific number of decimals. 158

10.4.2. Formatting of number with adding zeros. 158

10.4.3. Formatting of number to custom positive, negative and zero sections. 158

10.4.4. Formatting of number using custom CultureInfo and custom format 159

10.5. Formatting strings. 159

10.5.1. Simple string formatting with number parameter 159

10.6. Conversions. 160

10.6.1. Class Convert (many convertion methods) 160

10.6.2. Convert string to integer 160

10.6.3. Convert string to double. 160

10.6.4. Convert string to double using CultureInfo. 161

10.6.5. Convert string to date. 161

10.6.6. Use regular expression to find and replace string inside of string. 161

10.6.7. Converting string to DateTime using CultureInfo. 162

10.6.8. Convert time_t to DateTime. 163

10.6.9. Convert time_t to DateTime (shorter code) 163

10.6.10. Convert base64 encoded number to float 163

10.6.11. Convert file1/encoding1 into file2/encoding2. 164

10.7. Internationalization. 165

10.7.1. American Standard Code for Information Interchange (ASCII) 165

10.7.2. ISO 10646 & Universal Character Set 166

10.7.3. Unicode. 166

10.7.4. Class CultureInfo. 167

11.        Collections. 169

11.1.1. ArrayList 169

11.1.2. BitArray. 169

11.1.3. HashTable. 170

11.1.4. Queue. 170

11.1.5. SortedList 171

11.1.6. Stack. 171

12.        Time Operations. 172

12.1.1. Time measuring (TickCount and Ticks property) 172

12.1.2. Accurate time measuring. 172

13.        Windows Management Instrumentation (WMI) 173

13.1. CIM Schema. 174

13.2. WMI Architecture. 175

13.3. WMI tools. 175

13.3.1. WMI Object Browser 175

13.3.2. WMI CIM Studio. 176

13.3.3. WMI Event Registration Tool 177

13.3.4. WMI Event Viewer 177

13.4. WMI plug-in for Visual Studio .NET 2003. 177

13.5. List of WMI Classes. 178

13.5.1. Working with WMI on remote machine. 178

13.5.2. Get computer info (domain, model etc.) 179

13.5.3. Get computer info (vendor, UUID, type) 179

13.5.4. Get data about operating system.. 180

13.5.5. Logoff, shutdown, reboot computer 184

13.5.6. Get user’s desktop info. 186

13.5.7. Determine computer type (workstation, server, controller etc.) 187

13.5.8. Determine physical computer features. 187

13.5.9. Rename computer name. 190

13.5.10. Get processor info. 191

13.5.11. Get memory info. 199

13.5.12. Getting list of file shares on local machine. 200

13.5.13. Get logical disk info. 200

13.5.14. Get environment variables. 201

13.5.15. Get CD-ROM/DVD information. 201

13.5.16. Get boot configuration. 204

13.5.17. Find a service by its name. 205

13.5.18. Get list of running/stopped services. 205

13.5.19. Getting partition info. 206

13.5.20. Get list of user’s account from local machine/domain. 207

13.5.21. Get list of user groups from local machine/domain. 209

13.5.22. Get list of installed codec files. 210

13.6. Watching for event 211

13.6.1. Watching for newly started processes. 211

14.        XML.. 213

14.1. What is SGML?. 213

14.2. What is XML?. 213

14.3. What is XHTML?. 213

14.4. Forward-only reading and writing XML. 214

14.5. XmlTextReader 215

14.5.1. XML file “Sample.xml” used in following samples. 215

14.5.2. What is a XML schema?. 216

14.5.3. XSD file “Sample.xsd” used in following samples. 216

14.5.4. Load and read XML from URL. 217

14.5.5. Load and read XML from file. 217

14.5.6. Load and read XML from memory-stored data. 218

14.5.7. Handle whitespaces in XML. 218

14.5.8. Read specific attribute in XML. 219

14.5.9. Step over attributes in XML. 219

14.5.10. Write string data to XML file. 220

14.5.11. Write characters to XML file. 220

14.5.12. Write comments to XML file. 221

14.5.13. Write processing instructions to XML file. 221

14.5.14. Write attributes to XML file. 221

14.5.15. What is it a XML namespace?. 222

14.5.16. Write namespace to XML file. 222

14.5.17. Write namespace with prefix to XML file. 223

14.5.18. Set format options when writing to XML file. 223

14.5.19. Set a single quote as formatting option for XML file. 224

14.6. Document Object Model (DOM) 224

14.6.1. What is a XML document?. 224

14.6.2. Open XML document from URL. 224

14.6.3. Open XML document from file. 225

14.6.4. Open XML document with memory-stored data. 225

14.6.5. Insert nodes into XML document 225

14.6.6. Finding nodes by their names. 226

14.6.7. XPath classes in .NET 1.1. 227

14.6.8. Quering XML using XPath. 227

14.6.9. Sum attribute values using XPath expression. 228

14.6.10. List of XPath axes. 228

14.6.11. What is DTD?. 229

14.6.12. Validate XML against XSD (Schema) 229

14.6.13. Validate XML against DTD.. 230

14.7. Extensible Stylesheet Language for Transformation (XSLT) 231

14.8. XML Encryption. 231

15.        Computer environment 231

15.1.1. Local computer environment properties. 231

15.1.2. Creating shortcut in special folders (Desktop, StartMenu, Startup) 232

15.1.3. Determine actual system power status. 233

15.1.4. Enumerate installed printers on local machine. 235

15.1.5. Set default printer on local machine. 235

15.1.6. Enumerate network drives. 235

15.1.7. Integration with Windows (Help, Shotdown, Suspend, Control Panels) 236

15.1.8. Open Control Panel items. 237

15.1.9. Get folder items using Windows folder dialog. 238

16.        Other features. 238

16.1.1. Get string resource from dll library. 238

16.1.2. Handle events from other applications. 240

16.1.3. Beep in application. 240

16.1.4. Beep in application in Whidbey. 241

16.1.5. Programming access to attributes. 241

16.1.6. Get full-path & name of current process. 242

16.1.7. Programmatically create virtual website in IIS. 242

16.1.8. Get topmost window title using Win32 API 242

17.        ADO.NET.. 243

17.1. Architecture of ADO.NET.. 243

17.1.1. Connecting to SQL Server, Oracle, MySQL and others. 246

17.1.2. Watching connection state events and messages. 247

17.1.3. Executing SQL command and reading data in SqlDataReader 248

17.1.4. Executing stored procedure and reading data in SqlDataReader 249

17.1.5. Executing multiple SQL statements (batch) 249

17.1.6. Executing stored procedure and reading data from multiple result sets in SqlDataReader 250

17.1.7. Executing stored procedure and getting data in DataSet 251

17.1.8. Updating database data with changes in DataSet 253

17.1.9. Accessing Excel data using ADO.NET.. 254

17.1.10. List available SQL servers. 254

18.        ADO.NET & System.Xml 2.0 (Whidbey) 255

18.1. Summary of new features in ADO.NET 2.0. 255

18.1.1. Asynchronous Data Access. 255

18.1.2. Batch Updates. 255

18.1.3. DataSet Performance. 255

18.1.4. MARS (Multiple Active Results Sets) 255

18.2. Summary of new features in System.Xml 255

19.        Appendix A - Fast-track to C# language. 256

19.1. Basic terms and definitions in .NET & C#. 256

19.2. What is C#?. 257

19.3. Hello world. 257

19.4. Assemblies. 258

19.4.1. Locating of assemblies. 258

19.4.2. Assembly layout 258

19.5. Identifiers. 258

19.6. Types. 259

19.6.1. Hierarchy of types. 259

19.6.2. Predefined types. 260

19.6.3. Integral types. 260

19.6.4. Floating-point types. 262

19.6.5. Decimal type. 262

19.6.6. Bool type. 262

19.6.7. Object type. 262

19.6.8. String type. 263

19.6.9. Implicit conversions of numeric values. 263

19.6.10. Boxing and unboxing. 263

19.7. Variables & parameters. 264

19.7.1. Types of variables & parameters. 264

19.7.2. Default values. 266

19.7.3. Enum.. 267

19.7.4. Struct 267

19.8. Expressions & Operators. 269

19.8.1. Operators. 269

19.8.2. Overflow check operators. 270

19.8.3. Operator typeof 270

19.8.4. Operator is. 271

19.8.5. Operator overloading. 271

19.9. Preprocesor 272

19.10. Statements. 274

19.11. C# namespaces. 277

19.12. Exceptions & exception handling. 279

19.12.1. Throwing exceptions. 280

19.12.2. Exception classes. 280

19.12.3. Monitoring of exception performance. 281

19.12.4. Checked & unchecked exceptions. 282

19.13. Delegates and events. 283

19.13.1. Simple delegate usage. 283

19.13.2. Delegate declaration. 284

19.13.3. Delegate instanciation. 284

19.13.4. Final code with delegates. 284

19.13.5. Multicast delegates usage. 286

19.13.6. Final code with multicast delegates. 286

19.13.7. Event usage. 288

19.13.8. Final code with events. 288

19.14. Attributes. 289

19.14.1. Predefined attributes. 289

19.15. Multithreading & synchronization. 290

19.15.1. Semaphores & mutexes. 291

19.15.2. Thread architecture. 292

19.15.3. Multithreading in C#. 292

19.15.4. Race condition & deadlock. 294

19.15.5. Lock statement 295

19.16. Garbage Collection. 295

19.16.1. Collection of memory space. 295

19.16.2. Garbage Collector’s methods explained. 297

19.16.3. Hotspot JVM... 298

19.17. Unsafe code. 299

20.        C# version 2.0. 300

20.1. Partial types. 301

21.        Alphabetical bibliography. 302

21.1. Security & Cryptography. 302

21.2. .NET Environment 302

21.3. Interop. 303

21.4. Others. 303

 


3.  Windows Security

The Windows Security is very important to understand to see other principles in .NET because .NET security stand above Windows security. Also till Whidbey many security concepts are provided just in unmanaged environment and many Win32 methods must be wrapped into the .NET environment (they are not provided in .NET framework 1.1 so far).

3.1. Basic terms

In this section are described some of the basic terms illustrated on a figure below:

3.1.1. Principal

Entity that can be authenticated.

3.1.2. Authority

Entity authenticating principals and managing principals.

3.1.3. Authentication

Process when principal proves its identity. Who am I?

3.1.4. Authorization

Process when principal receives its rights to access specific protected resources. What can I do?

3.1.5. Trust

Trust in authority that it is able to authenticate principals.

3.1.5.1. Windows LSA Trust

When dealing with local Windows accounts then we must trust to LSA that authentication works well and user’s can be authenticated. Local security is very specifics and has many issues generally in all operating systems because of principal reasons.

3.1.5.2. Windows Domain Trust

Today’s world requires many ways of trust like in Windows trust is used as term when connecting domains and establishing some level of trust between them.

3.1.5.3. CA Trust

Trust in cryptography (not just OS security like in previous chapters) is very important concept and without it working with public keys would be impossible. That is why there must be one entity which we can trust and we derive our way of trust to other entities derived from first one (root).

3.1.6. Logon Session

Logon Session is created when principal gets authorized and when operating system assigns rights to him. For developers logon session are abstract concept (even when they are physically implemented in Windows) but they can be reached through tokens. Also very important is to understand difference between logon sessions because they are the cause of many problems developers are facing (typically when using impersonation in ASP.NET).

3.1.7. Token

Token is an object accessible to programmer and representing a logon session. Figure below represents an important data contained in token.

The next figure shows physical structure of token:

In Windows are system objects and those objects are connected to concept of token-based security. It means that any object in operating system has it’s own “lock” (in Windows terminology this “lock” is called as security descriptor) and when anybody wants to access this objects then must provide his “key” to open this lock. And user’s tokens are keys used to open “lock” to get access to some resource.

 

So what happens when user is logged into the system? When you type your password correctly and you authorize yourself as authorized user then system starts your session and creates user’s token together with its security ID (SID). This SID is located in domain controller (when user is a member of domain) or in a local SAM database (when accessing local computer).

SIDs are very important giving uniqueness in Windows environment; they are variable-length and they are composed from many parts:

 

Following two sample on methods LookupAccountSid and LookupAccountName are very important when working with international environments. Operating systems can be localized into different languages with different general names for objects and that is why SIDs are the best way how to identify those objects independently from current language version. Those samples present how SID and object names can be found (see 3.1.8 and 3.1.9).

3.1.8. Get SID for current identity

This sample is a modification of sample from www.pinvoke.net (see http://pinvoke.net/default.aspx/advapi32.LookupAccountName).

 

using System;

using System.Runtime.InteropServices;

using System.Text;

using System.Security.Principal;

 

class FindSidForuser

{

      const int NO_ERROR = 0;

      const int ERROR_INSUFFICIENT_BUFFER = 122;

 

      enum SID_NAME_USE

      {

            SidTypeUser = 1,

            SidTypeGroup,

            SidTypeDomain,

            SidTypeAlias,

            SidTypeWellKnownGroup,

            SidTypeDeletedAccount,

            SidTypeInvalid,

            SidTypeUnknown,

            SidTypeComputer

      }

 

      [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError = true)]

      static extern bool LookupAccountName (

            string lpSystemName,

            string lpAccountName,

            [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,

            ref uint cbSid,

            StringBuilder ReferencedDomainName,

            ref uint cchReferencedDomainName,

            out SID_NAME_USE peUse);               

 

 

      [DllImport("advapi32", CharSet=CharSet.Auto, SetLastError=true)]

      static extern bool ConvertSidToStringSid(

            [MarshalAs(UnmanagedType.LPArray)] byte [] pSID,

            out IntPtr ptrSid);

 

 

      [DllImport("kernel32.dll")]

      static extern IntPtr LocalFree(IntPtr hMem);

 

      [STAThread]

      static void Main(string[] args)

      {

            // get current user's identity

            WindowsIdentity wi = WindowsIdentity.GetCurrent();

            string accountName = wi.Name.ToString();

            byte [] Sid = null;

            uint cbSid = 0;

            StringBuilder referencedDomainName = new StringBuilder();

            uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;

            SID_NAME_USE sidUse;

 

            int err = NO_ERROR;

            // get data for size of buffer in cbSid and cchReferencedDomainName

            if (!LookupAccountName(null,accountName,Sid,ref cbSid,referencedDomainName,ref cchReferencedDomainName,out sidUse))

            {

                  err = Marshal.GetLastWin32Error();

                  if (err == ERROR_INSUFFICIENT_BUFFER)

                  {

                        Sid = new byte[cbSid];

                        referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);

                        err = NO_ERROR;

                        // !!! - FIND SID FOR USER !!!

                        if (!LookupAccountName(null,accountName,Sid,ref cbSid,referencedDomainName,ref cchReferencedDomainName,out sidUse))

                              err = Marshal.GetLastWin32Error();

                  }

            }

            if (err == 0)

            {

                  IntPtr ptrSid;

                  // convert sid value into well formatted string

                  if (!ConvertSidToStringSid(Sid,out ptrSid))

                  {

                        err = Marshal.GetLastWin32Error();

                        Console.WriteLine(@"Could not convert sid to string. Error : {0}",err);

                  }

                  else

                  {

                        string sidString = Marshal.PtrToStringAuto(ptrSid);

                        LocalFree(ptrSid);

                        Console.WriteLine(@"Found sid {0} : {1}",sidUse,sidString);

                  }

            }

            else

                  Console.WriteLine(@"Error : {0}",err);

      }

}

3.1.9. Get object name for SID

This sample is a modification of sample from www.pinvoke.net (see http://pinvoke.net/default.aspx/advapi32.LookupAccountSid).

using System;

using System.Runtime.InteropServices;

using System.Text;

 

class FindUserForSid

{

      const int NO_ERROR = 0;

      const int ERROR_INSUFFICIENT_BUFFER = 122;

 

      enum SID_NAME_USE

      {

            SidTypeUser = 1,

            SidTypeGroup,

            SidTypeDomain,

            SidTypeAlias,

            SidTypeWellKnownGroup,

            SidTypeDeletedAccount,

            SidTypeInvalid,

            SidTypeUnknown,

            SidTypeComputer

      }

 

      [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError = true)]

      static extern bool LookupAccountSid (

            string lpSystemName,

            [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,

            System.Text.StringBuilder lpName,

            ref uint cchName,

            System.Text.StringBuilder ReferencedDomainName,

            ref uint cchReferencedDomainName,

            out SID_NAME_USE peUse);   

 

      [STAThread]

      static void Main(string[] args)

      {

            StringBuilder name = new StringBuilder();

            uint cchName = (uint)name.Capacity;

            StringBuilder referencedDomainName = new StringBuilder();

            uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;

            SID_NAME_USE sidUse;

            // !!! Sid for BUILTIN\Administrators !!!

            byte[] Sid = new byte[] {1,2,0,0,0,0,0,5,32,0,0,0,32,2};

 

            int err = NO_ERROR;

            if (!LookupAccountSid(null,Sid,name,ref cchName,referencedDomainName,ref cchReferencedDomainName,out sidUse))

            {

                  err = System.Runtime.InteropServices.Marshal.GetLastWin32Error();

                  if (err == ERROR_INSUFFICIENT_BUFFER)

                  {

                        name.EnsureCapacity((int)cchName);

                        referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);

                        err = NO_ERROR;

                        if (!LookupAccountSid(null,Sid,name,ref cchName,referencedDomainName,ref cchReferencedDomainName,out sidUse))

                              err = System.Runtime.InteropServices.Marshal.GetLastWin32Error();

                  }

            }

            if (err == 0)

                  Console.WriteLine(@"Found account {0} : {1}\{2}",sidUse,referencedDomainName.ToString(),name.ToString());

            else

                  Console.WriteLine(@"Error : {0}",err);

      }

}

 

Then when user is logged and his session exist in operating system then there is always his access token with his SID.

Except SID access token contains other very important ACEs

 

 

SID, DACL and other parts of token forms user’s “key” that is used to open any lock of system resource when user is trying to access it.

3.2. Protecting system resources

Protecting system resources is important and very programmer or architect should understand this otherwise security holes can be created and this can lead to terrible security issues. This chapter presents some of the principles on this together with samples.

But first, try to test yourself about your knowdledge J

3.2.1. Test yourself on security & protection of system resources

What do you think about situation presented on figure below? User A wants to access a file.txt where he has aquired full access rights.

But the same user has no right for parent folder DirA. What do you think that will happen when UserA would try to read this file?

 

3.2.2. Rules behind propagation of rights on objects

3.2.3. Get ACLs/ACEs for a file

To run this sample you’ll need to download this wrapper provided on GotDotNet.

http://www.gotdotnet.com/Community/UserSamples/Download.aspx?SampleGuid=E6098575-DDA0-48B8-9ABF-E0705AF065D9 and add reference to it.

 

Namespaces:

using System;

using System.Runtime.InteropServices;

// wrapper for pinvoke on Win32 APIs

using Microsoft.Win32.Security;

 

Code:

public static void Main()

{

      string filename = @"C:\boot.ini";

      SecurityDescriptor secDesc = SecurityDescriptor.GetFileSecurity(

            filename,

            SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);

      using(secDesc)

      {

            foreach(Ace ace in secDesc.Dacl)

            {

                  Console.WriteLine("ACE SID:        {0} ", ace.Sid.CanonicalName);

                  Console.WriteLine("ACE Type:       {0} ", ace.Type);

                  Console.WriteLine("ACE AccessType: {0} (0x{0:X})", (FileAccessType)ace.AccessType);

            }

      }

      Console.ReadLine();

}

3.2.4. Set DACL for a file

To run this sample you’ll need to download this wrapper provided on GotDotNet.

http://www.gotdotnet.com/Community/UserSamples/Download.aspx?SampleGuid=E6098575-DDA0-48B8-9ABF-E0705AF065D9 and add reference to it.

 

Namespaces:

using System;

using System.Runtime.InteropServices;

// wrapper for pinvoke on Win32 APIs

using Microsoft.Win32.Security;

 

Code:

public static void Main()

{

      // you'll have to create file Sample.txt in root directory or change path appropriately

      string filename = @"C:\Sample.txt";

      // get security descriptor object for file with DACLs

      SecurityDescriptor secDesc = SecurityDescriptor.GetFileSecurity (filename, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);

      Dacl dacl = secDesc.Dacl;

      // add new ACE to DACLs (you must create user SampleUser in your system)

      dacl.AddAce (new AceAccessAllowed (new Sid ("SampleUser"), AccessType.GENERIC_ALL));

 

      // set DACLs to security descriptor

      secDesc.SetDacl(dacl);

 

      // update file security settings

      secDesc.SetFileSecurity(filename, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);

      Console.ReadLine();

}

4. Security Ratings

Security is the most important problem in our real life and also in our computers and information systems. That is why are defined standards and ratings that help us to recognize security level that has been checked and approved by qualified agencies and professionals.

 

This is the reason why the Department of Defense assigned responsibility for computer security to the Director of the National Security Agency (NSA), then DoD Computer Security Center was formed in 1981 and finally renamed to the National Computer Security Center (NCSC – www.radium.ncsc.mil). The primary task was defined in DoD Directive 5215.1, specifically tasked the center to establish and maintain…

 

“"... technical standards and criteria for the security evaluation of trusted computer systems that can be incorporated into the Department of Defense component life-cycle management process...”

 

The NCSC issued the first DoD Trusted Computer System Evaluation Criteria (TCSEC), commonly referred to as the "Orange Book." in August 1983. It was reissued in December 1985 as a DoD Standard (DOD 5200.28-STD). The TCSEC Standard serves the following purposes:

 

  1. Provide product manufacturers with a standard of security features to build into their products.
  2. Provide DoD components with a metric to evaluated how much trust can be placed in an automated information system for secure processing of classified or other sensitive data.
  3. Provide a basis for specifying security requirements in acquisition specifications.

 

The TCSEC Standard specifies degrees of trust with increasing level of trust ratings. Each level builds upon the previous one by adding security features and assurance to the user that the features work as designed.

 

Rating

Description

A1

Verified design.

B3

Security domains.

B2

Structured protection.

B1

Labeled security protection.

C2

Controlled access protection.

C1

Discretionary access protection.

D

Minimal protection.

4.1.1. What is a Common Criteria?

Common Criteria (CC) is an international standard - ISO 15408.  Common Criteria is the integration of information technology and computer security criteria.  The Common Criteria is used as the evaluation basis for security properties of IT products and systems.

4.1.2. Why is Common Criteria important?

ecent government and organizational mandates (within the US and other countries) require, and or encourage, Common Criteria Evaluations (CC) for computer security or computer security enabling products.  Computer security can best be defined as:

 

Operations that protect and defend information and information systems by ensuring their availability, integrity, authentication, confidentiality and non-repudiation.  Computer security also includes operations that provide for restoration of information systems by incorporating protection, detection, and reaction capabilities.

 

As a result, Common Criteria Evaluations have become a requirement for participation and growth in many government markets worldwide.  CC requirements are also starting to bleed into other markets such as finance and healthcare.

 

In order to participate in these markets, all of our computer security products and computer security enabling products will require an evaluation to determine if they need to go through the CC evaluation process.

5.  Security Concepts in .NET environment

5.1. Basic layout of .NET Framework – Security parts

.NET Framework security is composed from many technologies and approaches like:

 

The following figure presents basic layout of runtime environment and its security components.

Generally, the .NET platform is very advanced from security point of view, it brings many new approaches and today its one of the best (maybe the best) technical solution even when looking at security concepts. Today’s problems with viruses, buffer overrun and more can be solved by .NET environment and typical advantages will be seen with migration of Microsoft Office into the .NET environment (primitive viruses like MyDoom or similar will not be easy to write as now, we can hope J ).

The Microsoft .NET common language runtime (CLR) controls the execution of code, including just-in-time (JIT) compilation of Microsoft intermediate language code into native assembly code and garbage collection. Because of this CLR can prevent running code from inappropriate behavior and even to protect against security flaws.

As an assembly is loaded, JIT compiled, and executed, the security system verifies it for type safety and enforces code access security policy (see diagram).

5.2. Assembly

Assembly is a term used in .NET platform for a specific file generated by compilier after compilation. This file is similar to Windows binary files (at first sight with its extension .exe or .dll) and its layout is derived from standard PE file structure. But it is enhanced to support other features not included in native Windows binary files (for example assembly signature, version etc.).

5.2.1. Runtime security policy

Runtime security policy is essential to .NET security, it affects all assemblies running in .NET environment. But these is nothing magical on it – all assemblies are asking for some permissions which are needed to run and all  assemblies belond to specific groups depending on configured conditions. .NET environment sets 4 groups, in .NET terminology policy levels:

 

 

.NET security is similar to Windows security provided by operating system. User must provide his password and username, when he his authenticated against SAM database and access token is created and this token is used by process and threads to access system resources.

 

Similar approach is in .NET, when assembly is loaded it provides its evidences and asking for permissions based on those evidences. They are evaluated by runtime security policy management for each code group where assembly belongs to as it is configured for .NET environment (on figure below is sample code group with Intranet zone belonging to machine level security policy).

 

 

Finally assembly collects permissions from all code groups and when assembly is running and accessing any securable resource then those permissions are checked and access is granted or not.

Beside policy levels it is important to realize importance of code groups where permissions are defined. Code groups finally hold permissions and they associate assemblies with their permissions according to defined conditions (by default it is primary zone). On figure below is presented basic principle how code group works:

When policy levels work like an intersection of the same granted permissions, code groups join their permissions from one policy level.

Below is a sample with intranet application, when assembly is running in intranet environment (for instance run assembly from remote disk drive), then it is checked for all policy levels and assembly receives appropriate permissions (see figure).

In figure above application has been started from intranet (guess g:\sampleApp.exe). This application has a strong name and when started it is mapped to each levels and appropriate code groups. On enterprise level just All Code group is defined (the same is user level) with full trust permissions. On machine level are other sub-groups limiting permittions:

 

Code group

Description

My Computer (local)

Code is running on local machine and has full trust permissions.

Intranet

Code is executed from share or URL on LAN (or trusted enterprise network). Code has limited but still high permissions to access system resources.

Internet

Code is executed from internet and has limited permissions to a few resources like isolated storage, printing, dialogs.

Restricted

Code belongs to untrusted sites, it has no permissions.

Trusted

Code is executed from trusted sites and has the same permissions as in Internet code group.

 

Sample intranet application belongs to code group Intranet and will receive permissions defined in that group (environment variables, file dialog, isolated storage file, reflection, security, user interface, dns, printing, event log).

5.2.2. Types of security context for assemblies

Assembly must always run in security context which depends on behavior of assembly, code zone and type of assembly. Generally assembly can be running in three types of security contexts:

 

5.2.3. Generate key pair with sn.exe tool

First option is to generate file with keys which will be used to give a strong name to assembly:

 

 

sn -k myKey.snk

 

Second option is to store keys in CSP’s store, this is much more secure and recommended because keys are encrypted using DPAPI.

sn -i myKey.snk "SampleKeyStore"

5.2.4. Give an assembly a strong name

Assembly can be signed using file or CSP store, depending where keys are stored. If keys are stored in file then:

 

[assembly: AssemblyKeyFile(@"c:\@samples\MyKeys.snk")]

 

If keys are located in CSP store then use following attribute:

 

[assembly: AssemblyKeyName("SampleKeyStore")]

5.2.5. Delayed signing of assembly

This is a modification of signing an assembly with a strong name in previous chapter. There is different usage of keys because private key is not distributed and is kept hidden till final build is prepared and can be finally signed.

 

·        Locate a key pair generated by sn.exe tool.

·        Extract public key from myKey.snk file to new file myPublic.snk.

 

sn -p myKey.snk myPublic.snk

 

·        Set following attributes in AssemblyInfo.cs file:

 

[assembly: AssemblyDelaySign(true)]

// use public key file to sign

[assembly: AssemblyKeyFile("myPublic.snk")]

 

·        At the end of application development sign assembly with private key:

 

sn -r <assembly_name> myKey.snk

 

or

 

[assembly: AssemblyDelaySign(false)]

// use main key file to re-sign assembly with delay signing

[assembly: AssemblyKeyFile("c:\\signed\\myKey.snk")]

 

When assembly is not signed but AssemblyDelaySign is set to true, then in assembly is left enough space for latter signature. But problem is when assembly has to be installed into GAC (strong name is required). For this purpose is recommended to use a temporary private key and change it with final one when application is released.

5.2.6. List of permissions in policy levels

Namespaces:

using System;

using System.Security;

using System.Security.Policy;

using System.Collections;

 

Code:

static void Main(string[] args)

{

      IEnumerator policy = SecurityManager.PolicyHierarchy();

      while(policy.MoveNext())

      {

            PolicyLevel currentLevel = (PolicyLevel)policy.Current;

            IEnumerator namedPermission = currentLevel.NamedPermissionSets.GetEnumerator();

            while(namedPermission.MoveNext())

            {    

                  NamedPermissionSet permissionSet = (NamedPermissionSet)namedPermission.Current;

                  Console.WriteLine(permissionSet.Name);

                                                           

                  IEnumerator psEnumerator = permissionSet.GetEnumerator();

                  while (psEnumerator.MoveNext())

                  {

                        Console.WriteLine("\t" + psEnumerator.Current);

                  }

            }

      }

}

5.2.7. List of permissions assign to current assembly

Code:

using System;

using System.Reflection;

using System.Security;

using System.Security.Policy;

using System.Security.Permissions;

using System.Collections;

 

class AssemblyPermissions

{

      // name of buildin namedpermissionset for fulltrust

      const string sFullTrust = "FullTrust";

 

      static PermissionSet finalSet = new NamedPermissionSet("FinalAssemblySet");

      static PermissionSet permSet = null;

      // is it assembly with fulltrust permissions?

      static bool fullTrust = true;

 

      static void Main(string[] args)

      {

            IEnumerator policy = SecurityManager.PolicyHierarchy();

            while(policy.MoveNext())

            {

                  PolicyLevel currentLevel = (PolicyLevel)policy.Current;

                  CodeGroup group = currentLevel.ResolveMatchingCodeGroups(Assembly.GetExecutingAssembly().Evidence);

                  fullTrust &= ResolveGroups(group, currentLevel);

                  if (!fullTrust)

                  {

                        if (finalSet == null) finalSet = permSet;

                        else finalSet = finalSet.Intersect(permSet);

                        permSet = null;

                  }

            }

 

            if (fullTrust) Console.WriteLine("Assembly is running in full-trust mode.");

            else Output (finalSet);

      }

 

      static bool ResolveGroups(CodeGroup parent, PolicyLevel pl)

      {

            NamedPermissionSet nps = pl.GetNamedPermissionSet(parent.PermissionSetName);

            if (isFullTrust(nps)) return true;

 

            if (permSet == null) permSet = (PermissionSet)nps;

            else permSet = permSet.Union(nps);

 

            if (parent.Children.Count > 0)

            {

                  foreach (CodeGroup cp in parent.Children)

                  {

                        if (cp.Children.Count > 0) ResolveGroups(cp, pl);

                        else

                        {

                              NamedPermissionSet nps2 = pl.GetNamedPermissionSet(cp.PermissionSetName);

                              if (isFullTrust(nps2)) return true;

                              permSet = permSet.Union(nps2);

                        }

                  }

            }

 

            // fulltrust code group not found

            return false;

      }

 

      static bool isFullTrust(NamedPermissionSet nps)

      {

            if (nps.Name.Equals("FullTrust"))

            {

                  return true;

            }

            return false;

      }

 

      static void Output(PermissionSet ps)

      {

            IEnumerator psEnumerator = ps.GetEnumerator();

            while (psEnumerator.MoveNext())

            {

                  Console.WriteLine("\t" + psEnumerator.Current);

            }

      }

}

5.2.8. Get permission list for a custom evidence

Namespaces:

using System;

using System.Security;

using System.Security.Policy;

 

Code:

      static void Main(string[] args)

      {

            // set zone as Internet (default in runtime security settings with restricted permissions)

            Zone zone = new Zone(SecurityZone.Internet);

            // sample site of origin

            Site site = new Site("www.skilldrive.com");

 

            // create instance of evidence

            Evidence e = new Evidence();

            // add zone and site into evidence object

            e.AddHost(zone);

            e.AddHost(site);

            // resolve permissions

            PermissionSet permSet = SecurityManager.ResolvePolicy(e);

            Console.WriteLine(permSet);

      }

5.2.9. List of declarative permissions of assembly

.NET Framework provides tool permview.exe that can be used to get declarative permission requests in assembly.

This tool can be used as follows:

 

permview.exe assemblyName.exe

 

Output will be list of permissions declared in assemblyName.exe file.

5.2.10. Output assembly evidence list to XML file

Code:

using System;

using System.IO;

using System.Collections;

using System.Reflection;

 

namespace SampleAssembly

{

   class AsmEvidence

   {

         static void Main(string[] args)

         {

               // output file name

               string fileName = "asmevidence.xml";

               FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write);

               StreamWriter writer = new StreamWriter(stream);

 

               writer.WriteLine("<AssemblyList>", writer);

 

               // output current assembly to xml file

               outputAssembly(Assembly.GetExecutingAssembly(), writer);

 

               foreach (AssemblyName asmn in Assembly.GetExecutingAssembly().GetReferencedAssemblies())

               {

                     // output referencing assemblies to current assembly

                     outputAssembly(Assembly.Load(asmn), writer);

               }

              

               writer.WriteLine("</AssemblyList>");

               // close stream

               writer.Close();

         }

         static void outputAssembly(Assembly asm, StreamWriter writer)

         {

               writer.WriteLine("<Assembly name='{0}' version='{1}' codebase='{2}' culture='{3}'>", asm.GetName().Name, asm.GetName().Version,

                     asm.GetName().CodeBase, asm.GetName().CultureInfo);

               IEnumerator it = asm.Evidence.GetEnumerator();

               while (it.MoveNext())

               {

                     // dont output all raw data to keep file small and readable!!!!

                     if (it.Current.GetType() != typeof(System.Security.Policy.Hash))

                     writer.WriteLine(it.Current);

               }

               writer.WriteLine("</Assembly>");

         }

   }

}

5.2.11. List policy levels and code groups where current assembly belongs

Namespaces:

using System;

using System.Reflection;

using System.Security;

using System.Security.Policy;

using System.Collections;

 

Code:

class PolicyGroups

{

      static void Main(string[] args)

      {

            IEnumerator policy = SecurityManager.PolicyHierarchy();

            while(policy.MoveNext())

            {

                  PolicyLevel currentLevel = (PolicyLevel)policy.Current;

                  Console.WriteLine(currentLevel.Label);

                  CodeGroup group = currentLevel.ResolveMatchingCodeGroups(Assembly.GetExecutingAssembly().Evidence);

                  ResolveGroups(group);

            }

      }

 

      static void ResolveGroups(CodeGroup parent)

      {

            Console.WriteLine("\t" + parent.Name);

            if (parent.Children.Count > 0)

            {

                  foreach (CodeGroup cp in parent.Children)

                  {

                        if (cp.Children.Count >0) ResolveGroups(cp);

                        // code is not optimazed to work with many levels in console displaying

                        else Console.WriteLine("\t\t" + cp.Name);

                  }

            }

      }

}

5.3. Type safety, metadata and code verification

One of the most important part of .NET is the verifier which is the part of JIT compiler. Verifier ensures that executing code is safe and does some very important checks.

Programmers sometime are using scripting languages like JavaScript or VBScript allowing to use variables without declaration, initialization or assigning them very different types. This can lead to unintended behavior and possible security implications when program mysteriously crashes.

In compiled languages such as C and C++ is possible to do direct memory allocations or to take a pointer and do copy of memory data anywhere. This is a very powerful technique but also this is a source for many bugs and majority of security problems are cased by this.

.NET is very strict on type usage and verifier ensures that all types are declared properly and are properly used. CLR does checks on following issues:

 

·        Uninitialized variables

·        Unsafe variable casting

·        Out of bounds indexing of array

·        Buffer overrun

·        Bad use of pointers

 

Except type checking CLR is taking care of whole code when it loads it from assembly. But what is assembly? It is a package with PE (Portable Executable) format, where this format is similar to DLL structure. But this is extended with new areas like metadata, which has very useful data about classes, methods, fields, heaps, types contained in an assembly (more about PE format on MSDN).

The metadata can be seen as a detailed information section with data about variables, objects, types, security settings etc. One of the most important section of metadata are tables with definition of classes in assembly, table with methods and to this table is related table with method arguments (see diagram bellow).

This is a sample of code in assembly

 

      public class C

      {

            public void C1(string C11) {

                  // some code here

            }

}

 

which is then compiled to MS IL code stored in assembly. The metadata of that code contains following tables with appropriate code objects when each row is idenfied by a four-byte number – metadata token.

Type-safety verification is the cornerstone of .NET Framework security because it prevents access to unauthorized memory locations. This allows you to consistently enforce security policy. For example, code cannot overrun a buffer and cause execution to jump to an arbitrary memory location.

 

Metadata are very important to verify code – this process is called is code verification and occurs when assembly is being loaded. Those verifications are very important and should not be disabled (using SkipPermition

5.3.1. Get info about types in assembly

This is just simple sample about reflexion on assembly file and getting basic type info. For professional tool on reflection use .NET Reflector (see http://www.aisto.com/roeder/dotnet).

 

Namespaces:

using System;

using System.IO;

using System.Reflection;

 

Code:

class AssemblyInfo

{

      static void Main(string[] args)

      {

            // name of file with assembly information

            string fileName = "AssemblyInfo.txt";

            FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write);

            StreamWriter writer = new StreamWriter(stream);

 

            // use this to build large info file about assembly from .NET Framework

            // name of assembly file to examine

            // string asmFile = @"C:\Windows\Microsoft.NET\Framework\v1.1.4322\mscorlib.dll";

            // Assembly asm = Assembly.LoadFrom(asmFile);

 

            Assembly asm = Assembly.GetExecutingAssembly();

 

            // basic assembly properties

            writer.WriteLine("Location of assembly: " + asm.Location);

            writer.WriteLine("Assembly name: " + asm.FullName);

            writer.WriteLine("Entry point into assembly: " + asm.EntryPoint);

            writer.WriteLine("Assembly loaded from GAC: " + asm.GlobalAssemblyCache);

 

            writer.WriteLine("-------------- Resources --------------");

            // get resouce names for current assembly

            string[] names = asm.GetManifestResourceNames();

            for (int i=0; i<names.Length; i++)

            {

                  ManifestResourceInfo mri = asm.GetManifestResourceInfo(names[i]);

                  writer.WriteLine(mri.FileName + ", " + mri.ReferencedAssembly + ", " + mri.ResourceLocation);

            }

 

            writer.WriteLine("-------------- Types --------------");

            foreach (Type types in asm.GetTypes())

            {

                  // inpecting all classes, other types can be easily inspected with similar approach as demonstrated

                  if (types.IsClass)

                  {

                        writer.WriteLine("Class: "+types.Name);

                        BuildClass(types, writer);

                  }

            }

            // close file stream

            writer.Close();

      }

 

      private static void BuildClass(Type types, StreamWriter writer)

      {

            writer.WriteLine("\t"+"-------Constructors-------");

            foreach(ConstructorInfo ci in types.GetConstructors())

            {

                  writer.WriteLine("\t"+(ci.IsAbstract?"abstract ":"")+(ci.IsPrivate?"Private ":"")+(ci.IsPublic?"Public ":"")

                        +(ci.IsStatic?"Static ":"")+(ci.IsFinal?"Final ":"")+types.Name+", Parameters: "+ci.GetParameters().Length);

            }

            writer.WriteLine("\t"+"-------Methods-------");

            foreach(MethodInfo mi in types.GetMethods())

            {

                  writer.WriteLine("\t"+(mi.IsPrivate?"Private ":"")+(mi.IsPublic?"Public ":"")

                        +(mi.IsStatic?"Static ":"")+(mi.IsFinal?"Final ":"")+mi.Name+", Parameters: "+mi.GetParameters().Length);

            }

      }

}

5.4. Application domains

Application domains are very important enhancement in .NET platform providing better configuration, security and performance features. Domains can be understood as “smaller processes” running inside of process’s address space. In each process can be many domains representing different applications (typically this can be seen in web applications running on ASP.NET platform where each application is running inside of its own application domain).

5.4.1. Application domain boundaries and objects

Domain’s address space is protected by CLR separated from each others and can’t be accessed directly. Following picture shows how domains are separated within process and within whole system.

CLR protects every application domain and doesn’t allow them to access other domain’s address space. This can be done just by using web services, messaging or remoting (or by some direct memory operations around CLR environment).

When remoting is involved then there are two options how to pass objects between application domain boundaries:

 

·        Marshal-by-value (MBV)

Objects that are passed as MBV are serializable type and when object is passed then current state of object is serialized and new object in other domain is created and initialized with serialized values. Then in both domains exist two the same objects, but two instances.

This can be achieved by this declaration:

 

[System.Serializable]

class PassingMBV

{

// here are member variables and properties

}

 

When working with MBV objects then copy instances are created and to create a new instance in another application domain, metadata with object’s type must be loaded. This means that another assembly must be loaded and can’t be unloaded till domain is closed. This can lead to performance problems and that is why wrappers can be used instead of standard object’s instances.

For that purpose is designed class System.Runtime.Remoting.ObjectHandler which wraps object’s type and is used as a “proxy” that can be called to when object is needed.

 

 

 

·        Marshal-by-reference (MBR)

Objects that are passed as MBR are not cloned as MVB’s objects. First proxy of passed is created and this proxy is passed to other domain but still there is a connection with original object which is kept in first domain and the second one makes calls on this object using its proxy.

All MBR objects must be derived from System.MarshalByRefObject:

 

class PassingMBR : System.MarshalByRefObject

{

// here are member variables and properties

}

If objects are not MBV (serializable) or MBR (derived from MarshalByRefObject) then they can’t be passed between domain neither way.

5.4.2. Create application domain programmatically

Namespaces:

using System;

 

Code:

public static void Main(string[] args)

{

      AppDomainSetup setup = new AppDomainSetup();

      // setup path for a new appdomain, use base of current appdomain, runtime will use it to get private assemblies

      setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

      // this is  a appdomain configuration file

      setup.ConfigurationFile = "app_domain.config";

      // this is a list of directories with private assembly, it's relative to ApplicationBase

      setup.PrivateBinPath = "first;second;third";

      // download or not assemblies over the network (http)

      setup.DisallowCodeDownload = false;

      // if configuration file is provided then this enables to use policy section in config file

      setup.DisallowPublisherPolicy = true;

 

      AppDomain newDomain = AppDomain.CreateDomain(

            "SecondAppDomain",

            AppDomain.CurrentDomain.Evidence,

            setup);

}

5.4.3. Shadow copy enabled for application domain

Sometimes it’s important to keep executable file unlocked (for instance when compiling or publishing new assembly version in real-time environment). To achieve this, application domain must be setup to enable shadow copy feature, then assembly is cached by a system and not locked. This feature is used extensively by ASP.NET and can be used in many scenarios like custom deploying and versioning system etc.

 

Namespaces:

using System;

using System.Diagnostics;

 

Code:

static void Main(string[] args)

{

      // get current executable file name

      string file = Process.GetCurrentProcess().MainModule.FileName;

 

      // create setup for main domain (this will hold shadowed copy of assembly)

      System.AppDomainSetup mySetup = new System.AppDomainSetup();

      mySetup.ApplicationName = "ShadowingDomain";

      // enable Shadowcopying, MUST be string!

      mySetup.ShadowCopyFiles = "true";

      // which directory will be shadowcopied

      mySetup.ShadowCopyDirectories = AppDomain.CurrentDomain.BaseDirectory;

      // where will go copied files

      mySetup.CachePath = AppDomain.CurrentDomain.BaseDirectory;

 

      // new application domain to be shadowed

      AppDomain domain = AppDomain.CreateDomain(AppDomain.CurrentDomain.FriendlyName,

            AppDomain.CurrentDomain.Evidence,

            mySetup);

 

      // if shadowing is not started yet

      if (!AppDomain.CurrentDomain.ShadowCopyFiles) domain.ExecuteAssembly(file);

}

5.5. Security tools available in .NET

Here is alphabetical list of available security tools in .NET Framework 1.1.

 

Tool name

Description

MSDN reference

Certificate Creation Tool

(makecert.exe)

Generates X.509 certificates for testing purposes only.

Details

Certificate Manager Tool

(certmgr.exe)

Manages certificates, certificate trust list (CTLs) and certificate revocation list (CRLs). Works with local account and can help with local testing of security features using certificates. The same tool is available through Internet Explorer (Internet options->Content->Certificates).

Details

Certificate Verification Tool

(chktrust.exe)

Checks the validity of a file signed with an Authenticode certificate.

Details

Code Access Security Policy

(caspol.exe)

Enables users and administrators to modify security policy for the machine policy level, and the enterprise policy level.

Details

File Signing Tool

(signcode.exe)

Signs portable executable file (.dll or .exe) with an Authenticode digital signature and required permissions for code are added. This gives a control over security restrictions placed on executable files.

Details

Isolated Storage Tool

(storeadm.exe)

Lists or removes existing stores for the current user. Sample isolated storages for Windows XP are:

  • Roaming enabled: <SYSTEMDRIVE>\Documents and Settings\<user>\Application Data
  • Non-roaming: <SYSTEMDRIVE>\Documents and Settings\<user>\Local Settings\Application Data

See chapter 7.19.

Details

Permissions View Tool

(permview.exe)

This tool is used to view the minimal, optional, and refused permissions sets requested by an assembly.

Details

PEVerify Tool

(peverify.exe)

It helps to verify if generated MSIL code meets type safety requirements (generally this tool is not useful for application programmers but just the system ones, who write compilers or when developers wants to use compilers provided from third party and check the compiler’s output).

Details

Secutil Tool

(secutil.exe)

 

Details

Set Registry Tool

(setreg.exe)

 

Details

Software Publisher Certificate Test Tool

(cert2spc.exe)

 

Details

String Name Tool

(sn.exe)

 

Details

5.6. Code Access Security

Code access security is a basic part of .NET security concepts enabling to identify code privilege to run specific type of operation requiring some type of authorization to do it.

CAS divides code trust into different levels depending on where the code originates and also other aspects of its identity (like strong name etc.).

In .NET terminology this is called as permission and .NET defines three types of them:

 

Those types of permissions derive from System.Security.CodeAccessPermission abstract class. From that class are derived other classes representing different permissions like System.Data.Common.DBDataPermission (ensures that user has a security level adequate for accessing data), System.Security.Permissions.FileIOPermission (it controls the ability to access files and folders) and many others.

Also identity permissions are classes derived from System.Security.CodeAccessPermission abstract class. However, those classes are used for a different purpose when compared with code access permissions. Identity permissions enable to securely run assemblies according to type of their origin. For instance, when assembly is downloaded from Internet, then it can be identified by System.Security.Permissions.ZoneIdentityPermission class.

5.6.1. Stack-walk

Stack walk is a basic part of .NET security. It checks calling queue for a specific system resource where are some security concerns. When code is accessing protected system resource and demanding a permission to access it, then stack walk is performed.

When function is called then there is created a frame in .NET security stack where all data related to this call are stored.

On figure above is presented situation when assemblies are nested with method calls finally asking for some system resource. Assembly C is calling Demand() casing to run through all stack frames in stack (there are two frames for methods from assembly A and B) and check their permission set for permission 1. If permission 1 is granted then it is ok, if not then SecurityException will be raised like in case of assembly A (there is just permission 2).

Stack walk is very important to protect against “luring attack” when some malicious applications takes advantage of some other one with higher privileges and does something harmful. Stack walk is great to improve protection against such type of attack but still there are many issues which must be considered like:

 

5.6.2. Limit access permissions for a method

Namespaces:

using System;

using System.Security;

using System.Threading;

using System.Security.Permissions;

using System.Security.Principal;

 

Code:

class LimitPermission

{

      static void Main(string[] args)

      {

            try

            {

                  // -------- uncomment this to run app correctly, otherwise it will rise an exception!!!!

                  // -------- set appdomain to use windows principal!!!

                  // Thread.GetDomain().SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

                  MethodClass.MethodA();

            }

            catch (SecurityException se)

            {

                  Console.WriteLine("You are not authorized to access MethodA! Change role name.");

                  Console.WriteLine(se.Message);

            }

 

            Console.ReadLine();

      }

}

 

// caller must be in group of administrators

[PrincipalPermissionAttribute(SecurityAction.Demand, Role=@"BUILTIN\Administrators")]

class MethodClass

{

      public static void MethodA()

      {

            Console.WriteLine("OK! YOU ARE CORRECT USER! UseName: " + Thread.CurrentPrincipal.Identity.Name);

            Console.WriteLine("MethodA was called!");

      }

}

5.6.3. Add new code group to runtime security

Namespaces:

using System;

using System.Security;

using System.Security.Permissions;

using System.Security.Policy;

using System.Collections;

 

Code:

class TestAddCodeGroup

{

      static void Main(string[] args)

      {

            IEnumerator polItem = SecurityManager.PolicyHierarchy();

            // move to enterprise policy level

            polItem.MoveNext();

            // move to machine policy level

            polItem.MoveNext();

            // cast to policylevel

            PolicyLevel policy = (PolicyLevel)polItem.Current;

            // show name of current policy level

            Console.WriteLine("Current policy level working on: "+(policy.Label));

            // get root codegroup for machine policy level

            CodeGroup rootGroup = policy.RootCodeGroup;

            SiteMembershipCondition memberShip = new SiteMembershipCondition("www.skilldrive.com");

            PermissionSet permSet = policy.GetNamedPermissionSet("FullTrust");

            PolicyStatement policyStm = new PolicyStatement(permSet, PolicyStatementAttribute.Exclusive);

            UnionCodeGroup newGroup = new UnionCodeGroup(memberShip, policyStm);

            newGroup.Name = "SampleCodeGroup";

           

            // add new code group

            rootGroup.AddChild(newGroup);

            policy.RootCodeGroup = rootGroup;

            SecurityManager.SavePolicy();

      }

}

5.7. Role-based Security

5.7.1. Identity classes (also Whidbey)

 

5.7.2. Principal policy

In .NET are recognized two types principals: windows principal and generic principal. The first one is related to Windows security context and when current Windows principal is associated with access token tight to each process under Windows. When generic principal is involved then this security context is independent from under laying environment like Windows. By default .NET principal policy is set to generic identity and anonymous user. To change default settings call SetPrincipalPolicy() method on the beginning. See following samples where is described how principal policy can be set.

In first sample is presented code where on first two lines is accesed and initialized principal object of current thread.

 

using System;

using System.Threading;

using System.Security;

using System.Security.Principal;

 

 

public static void Main(string[] args)

{

      // get default principal - this will be GenericPrincipal

      IPrincipal principal = Thread.CurrentPrincipal;

      Console.WriteLine("Default principal: "+ principal.GetType());

 

      // change default policy to Windows, this will not work!!! principal object has been activated already!!!

 

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

 

      // output will be a GenericPrincipal again

      principal = Thread.CurrentPrincipal;

      Console.WriteLine("Changed principal: "+ principal.GetType());

}

 

Output of this program will be always GenericIdentity because this principal has been bind to current thread with call Thread.CurrentPrincipal and setting other principal policy will be ineffective. But consider next code section:

 

public static void Main(string[] args)

{

      // first change default policy to Windows principal

      AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

 

      // output will be WindowsPrincipal now!

      IPrincipal principal = Thread.CurrentPrincipal;

      Console.WriteLine("Changed principal: "+ principal.GetType());

}

 

Here is SetPrincipalPolicy() called first and it will be effective so console output will be WindowsIdentity class. If programmer needs to deal with different principals in application then new threads should be created and in ThreadStart delegate should be done their inicialization as shown in following sample:

 

using System;

using System.Threading;

using System.Security;

using System.Security.Principal;

 

class ManyPrincipalsSample

{

 

      private static PrincipalPolicy pp;

 

      public static void Main(string[] args)

      {

            // !!!!!!!!!!!!!!!!!!!!!!!!

            // whe this code is uncommented then all CurrentPrincipal objects will be GenericPrincipal

//          IPrincipal principal = Thread.CurrentPrincipal;

//          Console.WriteLine(principal.GetType());

 

            // set principal for thread t1 to WindowsPrincipal

            pp = PrincipalPolicy.WindowsPrincipal;

            // create a new thread

            Thread t1 = new Thread(new ThreadStart(SetThread));

            t1.Start();

            t1.Join();

 

            // set principal for thread t2 to UnauthenticatedPrincipal

            pp = PrincipalPolicy.UnauthenticatedPrincipal;

            Thread t2 = new Thread(new ThreadStart(SetThread));

            t2.Start();

            t2.Join();

 

            // set principal for thread t3 to NoPrincipal, no principal object will be created!!!

            pp = PrincipalPolicy.NoPrincipal;

            Thread t3 = new Thread(new ThreadStart(SetThread));

            t3.Start();

            t3.Join();

      }

 

      // this is a delegate for newly created thread object (ThreadStart)

      public static void SetThread()

      {

            // set principal policy of newly created thread

            Thread.GetDomain().SetPrincipalPolicy(pp);

            // get principal object

            IPrincipal principal = Thread.CurrentPrincipal;

            // output principal object's name

            if (principal != null) Console.WriteLine(principal.GetType());

            else Console.WriteLine("No principal object.");

      }

}

5.7.3. Principal classes

5.7.4. Using GenericPrincipal class

Namespaces:

using System;

using System.Threading;

using System.Security.Principal;

 

Code:

class SampleGeneric

{

      private static string user = "MyLovingUser";

 

      public static void Main(string[] args)

      {

            IIdentity gi = new GenericIdentity(user, "MyAuthenticationType");

            string[] roles = null;

            GenericPrincipal gp = new GenericPrincipal(gi, roles);

            Thread.CurrentPrincipal = gp;

 

            // call method

            SomeMethod();

      }

 

      private static void SomeMethod()

      {

            IPrincipal principal = Thread.CurrentPrincipal;

            if (principal.Identity.Name.Equals(user))

            {

                  Console.WriteLine("Jooooo, je to von! :) ");

            }

      }

}

5.7.5. Get list of groups for current thread’s identity

Namespaces:

using System;

using System.Collections;

using System.Threading;

using System.Security.Principal;

 

Code:

static void Main(string[] args)

{

      ArrayList array = new ArrayList();

      // set appdomain to bind threads to windows identity objects, then windows security api can be used

      AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

      // WindowsPrincipal is default principal object

      WindowsPrincipal wp = (WindowsPrincipal) Thread.CurrentPrincipal;

 

      // create array of mapped Builtin groups provided by .NET FW

      // there can be SecurityException when builtin group RID doesnt exist in all Windows systems

      try

      {

            // if (wp.IsInRole(WindowsBuiltInRole.AccountOperator)) array.Add("Managed - Account Operator");

            if (wp.IsInRole(WindowsBuiltInRole.Administrator)) array.Add("Managed - Administrator");

            if (wp.IsInRole(WindowsBuiltInRole.BackupOperator)) array.Add("Managed - Backup Operator");

            if (wp.IsInRole(WindowsBuiltInRole.Guest)) array.Add("Managed - Guest");

            if (wp.IsInRole(WindowsBuiltInRole.PowerUser)) array.Add("Managed - Power User");

            // if (wp.IsInRole(WindowsBuiltInRole.PrintOperator)) array.Add("Managed - Print Operator");

            if (wp.IsInRole(WindowsBuiltInRole.Replicator)) array.Add("Managed - Replicator");

            // if (wp.IsInRole(WindowsBuiltInRole.SystemOperator)) array.Add("Managed - System Operator");

            if (wp.IsInRole(WindowsBuiltInRole.User)) array.Add("Managed - User");

      }

      catch (ArgumentException se)

      {

            Console.WriteLine(se.Message);

      }

 

      // user can check if account is in builtin roles by those command (they should be changed appropriatelly to reflect used builtint accounts)

      if (wp.IsInRole(@"BUILTIN\Administrators")) array.Add("String - Administrators");

      if (wp.IsInRole(@"BUILTIN\Guests")) array.Add("String - Guests");

      if (wp.IsInRole(@"BUILTIN\Users")) array.Add("String - Users");

      IEnumerator en = array.GetEnumerator();

      while(en.MoveNext())

      {

            Console.WriteLine(en.Current);

      }

}

5.7.6. Get current user name

This sample presents two different approaches to getting current user information.

 

Namespaces:

using System;

using System.Net;

using System.Security.Principal;

 

Code:

static void Main(string[] args)

{

      // get info about current user using Environment class

      Console.WriteLine(Environment.UserDomainName + @"\" + Environment.UserName);

 

      // --------------------------

 

      // get current user from WindowsIdentity class

      WindowsIdentity user = WindowsIdentity.GetCurrent();

      // output current user name

      Console.WriteLine(user.Name.ToString());

}

5.7.7. Impersonate as another user

using System;

using System.Runtime.InteropServices;

using System.Security.Principal;

 

class ImpersonateUser

{

      // this implementation doesn't handle GetLastError function to catch error messages, it should be implemented in standard application

 

      // mapping of Win32 function to logon under another account

      [DllImport("advapi32.dll", SetLastError = true)]

      public static extern bool LogonUser(

            String lpszUsername,

            String lpszDomain,

            String lpszPassword,

            int dwLogonType,

            int dwLogonProvider,

            ref IntPtr phToken);

 

      // this will duplicate access token based on current user's one

      [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]

      public extern static bool DuplicateToken(

            IntPtr ExistingTokenHandle,

            int SECURITY_IMPERSONATION_LEVEL,

            ref IntPtr DuplicateTokenHandle);

 

      [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

      public extern static bool CloseHandle(IntPtr handle);

 

      static void Main(string[] args)

      {

            const int LOGON32_LOGON_INTERACTIVE = 2;

            const int LOGON32_PROVIDER_DEFAULT = 0;

            const int SecurityImpersonation = 2;

            // handle of access token of current user

            IntPtr token = IntPtr.Zero;

            // new token based on the old one

            IntPtr duplicateToken = IntPtr.Zero;

 

            // this method returns handle to access token of user we want to use to logon, user is check just in local database

            if (LogonUser("TestUser", ".", "Test1234]", LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token))

            {

                  // token is duplicated according to the token of impersonated user

                  if (DuplicateToken(token, SecurityImpersonation, ref duplicateToken))

                  {

                        Console.WriteLine("Current user name: " + WindowsIdentity.GetCurrent().Name);

                        // new identity is created

                        WindowsIdentity newIdentity = new WindowsIdentity(duplicateToken);

                        // !!!! This is the impersonation !!!!

                        WindowsImpersonationContext impersonatedUser = newIdentity.Impersonate();

                        Console.WriteLine("Current user name: " + WindowsIdentity.GetCurrent().Name);

                        // return to the old user

                        impersonatedUser.Undo();

                        Console.WriteLine("Current user name: " + WindowsIdentity.GetCurrent().Name);

 

                        // close handles to tokens

                        CloseHandle(token);

                        CloseHandle(duplicateToken);

                  }

                  else { Console.WriteLine("Error duplicate."); }

            }

            else { Console.WriteLine("Error logon."); }

      }

}

5.7.8. Declarative principal permissions for Windows roles

This sample demonstrates usage of declarative principal permissions integrated with Windows groups. There is class MethodClass with MethodA and this class demands its callers to be members of group of administrators. To run it correctly, Thread line must be uncommented otherwise application will rise an exception because caller will not be authorized to use class MethodClass.

 

Namespaces:

using System;

using System.Security;

using System.Threading;

using System.Security.Permissions;

using System.Security.Principal;

 

Code:

class TestPrincipalPermission

{

      static void Main(string[] args)

      {

            try

            {

                  // -------- uncomment this to run app correctly, otherwise it will rise an exception!!!!

                  // -------- set appdomain to use windows principal!!!

                  // Thread.GetDomain().SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

                  MethodClass.MethodA();

            }

            catch (SecurityException se)

            {

                  Console.WriteLine("You are not authorized to access MethodA! Change role name.");

                  Console.WriteLine(se.Message);

            }

      }

}

 

// caller must be in group of administrators

[PrincipalPermissionAttribute(SecurityAction.Demand, Role=@"BUILTIN\Administrators")]

class MethodClass

{

      public static void MethodA()

      {

            Console.WriteLine("MethodA was called!");

      }

}

5.7.9. Declarative principal permissions for custom roles

Namespaces:

using System;

using System.Security;

using System.Threading;

using System.Security.Permissions;

using System.Security.Principal;

 

Code:

class TestPrincipal

{

      static void Main(string[] args)

      {

            try

            {

                  GenericPrincipal gp = new GenericPrincipal(new GenericIdentity("Jan Seda"), new string[] {"SampleRole"});

                  // set generic principal object, this will be used to authenticate to MethodClass

                  Thread.CurrentPrincipal = gp;

                  // call method

                  MethodClass.MethodA();

            }

            catch (SecurityException se)

            {

                  Console.WriteLine("You are not authorized to access MethodA! Change role name.");

                  Console.WriteLine(se.Message);

            }

      }

}

 

// caller must have "SampleRole"

[PrincipalPermissionAttribute(SecurityAction.Demand, Role=@"SampleRole")]

class MethodClass

{

      public static void MethodA()

      {

            Console.WriteLine("MethodA was called!");

      }

}

5.7.10. List running processes and user accounts

Namespaces:

using System;

using System.Runtime.InteropServices;

using System.Security.Principal;

using System.Collections;

using System.Diagnostics;

 

Code:

class ListOfProcessAccounts

{

      class ProcessIdentity

      {

            public Process Process;

            public WindowsIdentity Identity;

 

            public ProcessIdentity(Process process, WindowsIdentity identity)

            {

                  this.Process = process;

                  this.Identity = identity;

            }

      }

 

      [Flags]

            enum TOKEN_ACCESS : uint

      {

            TOKEN_ASSIGN_PRIMARY = 0x0001,

            TOKEN_DUPLICATE = 0x0002,

            TOKEN_IMPERSONATE = 0x0004,

            TOKEN_QUERY = 0x0008,

            TOKEN_QUERY_SOURCE = 0x0010,

            TOKEN_ADJUST_PRIVILEGES = 0x0020,

            TOKEN_ADJUST_GROUPS = 0x0040,

            TOKEN_ADJUST_DEFAULT = 0x0080,

            TOKEN_ADJUST_SESSIONID = 0x0100,

            TOKEN_READ = 0x00020000 | TOKEN_QUERY,

            TOKEN_WRITE = 0x00020000 | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT,

            TOKEN_EXECUTE = 0x00020000,

      };

 

      [DllImport("Advapi32.dll", SetLastError = true)]

      extern static int OpenProcessToken(IntPtr processHandle, TOKEN_ACCESS desiredAccess, out IntPtr tokenHandle);

 

      [DllImport("kernel32.dll", SetLastError = true)]

      extern static bool CloseHandle(IntPtr handle);

 

      static ProcessIdentity[] GetProcessesIdentities()

      {

            ArrayList list = new ArrayList();

 

            foreach( Process process in Process.GetProcesses() )

            {

                  try

                  {

                        IntPtr token = IntPtr.Zero;

                        if( OpenProcessToken(process.Handle, TOKEN_ACCESS.TOKEN_QUERY, out token) == 0 )

                        {

                              throw new ApplicationException("Can't open process token for: " + process.ProcessName);

                        }

 

                        list.Add(new ProcessIdentity(process, new WindowsIdentity(token)));

                        CloseHandle(token);

                  }

                  catch( Exception ex )

                  {

                        list.Add(new ProcessIdentity(process, null));

                        System.Diagnostics.Debug.WriteLine(ex.Message);

                  }

            }

 

            return (ProcessIdentity[])list.ToArray(typeof(ProcessIdentity));

      }

 

      static void Main(string[] args)

      {

            ProcessIdentity[] normalProcIDs = GetProcessesIdentities();

            foreach( ProcessIdentity procid in normalProcIDs )

            {

                  if( procid.Identity != null )

                  {

                        Console.WriteLine("{0} running under {1}", procid.Process.ProcessName, procid.Identity.Name);

                  }

                  else

                  {

                        Console.WriteLine("{0} *probably* running under SYSTEM", procid.Process.ProcessName);

                  }

            }

      }

}

6. Cryptography & Security

6.1. Buffer Overrun

Buffer overrun is one of the most common and the most dangerous security risks. This vulnerability exists because of low level of memory management that exists in languages like C/C++. Generally, buffer overruns occurs when the size of a variable is not large enough to hold a given value and the memory buffer is overwritten with inappropriate values. There are three kinds of buffer overruns:

So how buffer overrun works? The basic principle can be seen on the following diagram

As can be seen on a diagram, green data panel is correct with its size. It holds 256 bytes and its stccpy()s to stack as appropriately. But because there is no size check in method someMethod, it is possible to send unlimited data, like in second example char[260]. The attacker can do some tests on buffer overflow and if he is lucky he can override system values and get weird results, in better case he gets just access violation error and process shuts down. In case hacker makes successful attack, he will be able to overwrite the method’s return address and execute some arbitrary code with the same privileges as the running process.

6.1.1. CodeRed Worm, Buffer Overrun attack

In July 2001 worm CodeRed started to propagate itself over the Internet and affected Microsoft IIS. The problem was cased by usage of Unicode and ANSI format, when developer writing a small part of code in IIS forgot to do a check on passed parameter and its size calculated to Unicode format (its two bytes long, not one byte as ANSI).

This is a sample of affected code:

...

// cchAttribute is a byte count of user input

WCHAR wcsAttribute[200];

if (cchAttribute >= sizeof wcsAtrribute)

      THROW (CException(DB_E_ERRORSINCOMMAND));

DecodeURLEscapes((BYTE*) pszAttribute, cchAttribute,

                         wcsAttribute, webServer.CodePage());

...

As been seen, first two rows are the reason for existence of CodeRed worm. There is a check on cchAttribute size, where sizeof is calculated on ANSI size of wcsAttribute. But WCHAR is Unicode and that is why it is two time bigger that developer was expecting it should be. With this error hacker has 200 bytes available for attack.

This error can be fixed by a following check:

...

// cchAttribute is a byte count of user input

WCHAR wcsAttribute[200];

if (cchAttribute >= sizeof wcsAtrribute / sizeof WCHAR)

      THROW (CException(DB_E_ERRORSINCOMMAND));

...

When wcsAttribute is divided by size of WCHAR, then we get a correct value and check is fine. If code should be absolutely correct we should make division by a first array member:

...

// cchAttribute is a byte count of user input

WCHAR wcsAttribute[200];

if (cchAttribute >= sizeof wcsAtrribute / sizeof wcsAttribute[0])

      THROW (CException(DB_E_ERRORSINCOMMAND));

...

and not by using WCHAR because value of WCHAR can be changed and our code would be again insecure. With this approach we are fine for all times (we can hope for some time J).

6.1.2. SQLSlammer

Another type of very dangerous worm is SQLSlammer that used a security hole in Microsoft SQL Server 2000, but this attack used buffer underrun when UDP packets were sent to port 1433 with length of 376 bytes. This cased buffer underrun and worm was loaded as resident program and started to scan and send other internet addresses.

6.2. Algorithms for Encryption

6.2.1. Well Known Algorithms for Symmetric Encryption

Algorithm

Description

Data Encryption Standard (DES)

(see chapter 7.10.4)

Relatively slow, key - 56 bits, not suitable for high-security encryption

Triple DES

Performs three DES roundtrips, equivalent of 168-bit key, relatively slow, widely used

Advanced Encryption Standard (AES)

128-, 192-, 256-bit keys, current standard used by U.S. government

International Data Encryption Algorithm (IDEA)

128-bit key, requires licensing for commercial use

RC2

8- to 128-bit keys, stream cipher

6.2.2. Well Known Algorithms for Asymmetric Encryption

Algorithm

Description

RSA

384 – 16384 bit keys, used to encrypt data and generate digital signatures, de-facto standard for asymmetric encryption

Diffie-Helman

768 – 1014 bit keys, fast asymmetric algorithm

ElGamal

 

DSA

512 – 1024 bit keys, only supports digital signatures

6.2.3. Well Known Hash Algorithms

Algorithm

RFC

Description

Message Digest 4 (MD4)

RFC 1320

128 bits, very fast, appropriate for medium security usage

Message Digest 5 (MD5)

RFC 1321

128 bits, fast, more secure then MD4

Secure Hash Standard (SHA-1)

FIPS PUB 180-1

160 bits, slower then MD5, standard for U.S. government

 

6.3. Digital Certificates

A digital certificate is an item of information that binds the details about individual or organization to the individual’s or organization’s public key. Digital certificates can be used to verify the identity of both clients and servers.

A digital certificate is a binary structure that contains information about the holder of a public key. The most common form of certificate is the X.509 certificate. There are three versions of this certificate:1, 2 and 3.

6.4. Secure Communication Standards

6.4.1. IPSec (Internet Protocol Security)

IPSec is a framework of open standards you can use to ensure secure, private communication over IP networks by using a combination of cryptography security services that are negotiated between client and server. IPSec is build by using other encryption standards, including symmetric algorithms such as DES, 3DES and RC5 and hashes such as MD5 and SHA-1.

6.4.2. Kerberos

Kerberos is one of the most important security protocols. His name is derived from mythological three-headed dog guarding entrance into the Hades. But this is mythology but in computer science Kerberos means a new standard developed by MIT to keep primary network authentication secure and prevent sending passwords as plaintext over the network.

6.4.3. SSL (Secure Socket Layer)

SSL (Secure Sockets Layer) is a protocol for session-based encryption and authentication. The advantage of is that it lends itself to applications that require a trust relationship between client and server and want to defeat themselves from eavesdropping, tampering and message forgery.

SSL can be thought of as a pipeline between a client and server protecting transferred data.

6.4.3.1. History of SSL

SSL protocol was developed by Netscape in 1994 and now it is widely accepted as a secure standard for internet communication (today it’s implemented in nearly all web servers and browsers). The protocol comes in three versions:

 

 

SSL version 3 is the predominant protocol used worldwide as an secure standard. This version solves many issues like requesting a new handshake from client or from server in any time to change keys used to encipher client-server communication.

6.4.3.2. Description of SSL

In TCP stack of protocols SSL is at the transport layer and is independent of the application protocol. That is why application protocols can use SSL as it is shown in figure bellow.

 

 

SSL encryption relies on the server’s public key and private key. The private key exists only on the Web server and is used by the Web server to encrypt and decrypt secure messages. The public key exists on any client computer that has installed a certificate for that Web server. After the public key is installed, the user can send encrypted messages to, and decrypt messages received from, the Web server.

When SSL is used, the following occurs:

  1. The user browses to the secure Web server’s site.
  2. 2. The browser creates a unique session key and encrypts it by using the Web server’s public key, which is generated from the root certificate. Each session key that the Web server’s certificate generates is unique. Therefore, even if a hacker has the same certificate installed on their browser, the hacker cannot decrypt the message. The browser where the encrypted message originated cannot decrypt the message. Only the Web server with the appropriate private key can decrypt the message.
  3. The Web server receives the message and decrypts it by using its private key. This phase of SSL communication is often called the SSL handshake. A hacker may intercept a message protected with SSL. However, the hacker cannot decrypt the message, because the hacker does not have the Web server’s private key.
  4. After the connection is established, all communication between the browser and the Web server is secure.
  5. When the session ends, the session key is destroyed.

6.4.3.3. SSL Handshake

But thse steps are a very short and brief description of what happens when SSL is getting involved. But sometimes (primary when calling from application other services like .aspx pages and we want to use SSL from application).

That is why deeper knowledge is essential. One of the most asked question on SSL is regarding the SSL Handshake when connection is established. That is why there are the steps of handshake to understand this process:

 

  1. The client sends the server client’s SSL version number, proposed type of cipher, session specific data and other data required by server to communicate with the client.
  2. The server sends to client the same request with the same type of data: the server’s SSL version, type of cipher, session specific data and other data required by client to communicate with the server. The server also sends the server’s certificate and client can send its own client certificate if it’s required by server to access some resources.
  3. The client uses data sent by server to authenticate the server according to process in figure below (more details on Microsoft’s web site):

  1. The client uses all data generated in handshake up to now to create pre-master secret for current session (pre-master secret is 48 bytes large). This “pre-master” is encrypted by the server’s public key from server’s certificate (see step 2) and sends it to the server. The pre-master secret is
  2. This is an optional step in handshake – client authentication. In case that server has requested client’s authentication to access some resources and in such a situation the client’s certificate is used. The clients signs data known to both client and server and together he sends the client’s certificate along with the pre-master secret. When client’s authentication is required then server runs according to following diagram:

  1. When client is authenticated (when required) server uses its private key to decipher the pre-master secret from and then generates master secret. This happens on both sides – on the client and the server simultaneously:

"master_secret =

       MD5(pre_master_secret + SHA('A' + pre_master_secret +

           ClientHello.random + ServerHello.random)) +

       MD5(pre_master_secret + SHA('BB' + pre_master_secret +

           ClientHello.random + ServerHello.random)) +

       MD5(pre_master_secret + SHA('CCC' + pre_master_secret +

           ClientHello.random + ServerHello.random));"

  1. Both the client and the server use the master secret to generate session keys, which are used for symmetric encryption used during the SSL’s session.
  2. Finally the client sends to server a message informing that future messages will be encrypted by symmetric key.

7. Cryptography

7.1. Basic terms in cryptography

Cryptography – is the science concerting ciphering and deciphering of some data to protect it from unauthorized access.

Steganography – this is a collection of techniques hiding data (for instance encrypted data) into some medium carrying them (like microfilm, images etc.). Generally steganography isn’t difficult to break (when compared with cryptography), but it hides data that could become a target for attack. Generally steganography is used together with cryptography to cover the encrypted data by some unimportant wrapper (like image) and not to show them to possible attacker to use on them some cryptoanalytic attacks.

Cryptoanalysis – this is the science related to cryptography, but its purpose isn’t to protect data but to find ways how to decrypt data without knowledge of secret key used for encryption.

Plain text – this term defines data, that are clear before encryption (generally readable text or similar form of data).

Cipher text – when plain text is encrypted, then cipher text is created. Input data (plain text) are now transformed to cipher text form, which is unreadable to unauthorized person.

Symmetric algorithms – A symmetric algorithm uses the same key for encryption and also for decryption of the same data.

Asymmetric algorithms – An asymmetric algorithm is based on research of Diffie and Hellman in 1976, when they published the first publication on this topic. The basic principle is presence of private and public keys when data can be encrypted and decrypted just by the adequate pair of those keys.

Confusion – is a method of mixing-up input data so it’s difficult to “mix” them back (decipher), this process is based on substitution when letter or a bit array is exchanged by another.

Diffusion – is a principle when every change in a plain text cases many changes in cipher text and this is based on transposition when letter or a bit array order is changed. Together with confusion, diffusion is a basic part of cryptographic algorithms because together they create too many alternatives when used (just imagine that 26 characters in alphabet used for substitution of plain text N characters long give (26n)! of cipher text modifications).

Initialization vector – when using block ciphers like DES encrypt/decrypt data in blocks when for block n is used defined encryption operation together with key and n-1 block. This prevents from finding any patterns in encryption process. But problem is with first block where is no previous block. That is why initialization vector is defined and it is block with random data giving higher secrecy.

Salt – salt is a term used for non-secret bits which are added to data before encryption. When salt is used then attacks with precomputed databases or plain-text attacks are much harder.

7.2. A little bit of history

7.2.1. Caesar cipher

Cryptography is the word derived from Greek words kỳptus (hidden) and gráphein (write). The first use of cryptography has been identified to 1900 BC in Egypt. Since them cryptography made a big progress in its algorithms and techniques, but the purpose is always the same. One of the most famous ciphers is Caesar cipher, which has been extensively used by Julius Ceasar who even developed it. This cipher is very easy but efficient, it is based on character rotation, when each character is mapped to another one according to a number of rotation steps (see figure below)

When rotation is finished, then there are two patterns available. The first one is the normal with alphabet as we know it (the green pattern). The second one (blue pattern) is the pattern after 2 round of shifting. It’s obvious how cipher works now.

 

Here is a code representing Caesar cipher (code is not optimized, but it is easy to reduce its size):

 

using System;

using System.Text;

 

class CaesarCipher

{

      static void Main(string[] args)

      {

            string ciphertext = encrypt(".NET in Samples", 2);

            Console.WriteLine("Ciphertext: " + ciphertext);

            Console.WriteLine("Plaintext: " + decrypt(ciphertext, 2));

      }

 

      public static string encrypt(string plaintext, int key)

      {

            StringBuilder ciphertext = new StringBuilder();

            // for simplicity this implementation works just with uppercases

            char[] c = plaintext.ToUpper().ToCharArray();

 

            for (int i = 0; i < c.Length; i++)

            {

                  if (c[i] < 'A' || c[i] > 'Z') ciphertext.Append(c[i]);

                  else

                  {

                        // shift the character accoring to key and add it to cipher text

                        ciphertext.Append(shift((int)c[i], key));

                  }

            }

            return ciphertext.ToString();

      }

 

      public static string decrypt(string ciphertext, int key)

      {

            StringBuilder decipher = new StringBuilder();

            // for simplicity this implementation works just with uppercases

            char[] c = ciphertext.ToUpper().ToCharArray();

 

            for (int i = 0; i < c.Length; i++)

            {

                  if (c[i] < 'A' || c[i] > 'Z') decipher.Append(c[i]);

                  else

                  {

                        // now minus is used with key to invert the reverted values

                        decipher.Append(shift((int)c[i], -key));

                  }

            }

            return decipher.ToString();

      }

 

      // !!! algorithm is not optimized and could be written in one line, this is JUST for sampling purposes

      private static char shift(int iC, int key)

      {

            // subtract value of the lowest character in ASCII, it is 'A'

            iC = iC - 'A';

            // add key to shift the character as is needed

            iC = iC + key;

            // check if it is out of bounds, then return a reminder which represents shift character to a new possition

            iC = iC % 26;

            // add ASCII value of 'A' character to make correct representation as on the beginning

            iC = iC + 'A';

            return (char)iC;

      }

}

 

Caesar cipher is quite easy to brake because there are only 26 possible permutations before finding intelligible word. That is why its practical usage is zero, but it’s important to understand it and to know the historical development of cryptography.

7.2.2. Progress in cryptography

The substitution ciphers are just the beginning of development of cryptography algorithms. Major progress has been made during World Wars, when cryptography and cryptanalysis played a very important role. Notoriously known is decoding of message sent from German Foreign Minister Arthur Zimmerman to German Minister to Mexico offering Mexico United States’ land in exchange for support to Germany over the World War I. When Americans deciphered the message, they joined the war thereafter against Germany.

Second historically known case of cryptography importance is during World War II, when Germans used special machine called Enigma (developed by Arthur Scherbius), to encrypt their communication with U-boats. When Enigma cipher was broken, nearly all U-boats had been destroyed and this was very important for survival of United Kingdom and destruction of Bismark.

All of these algorithms were sophisticated and hard to brake and their mechanism was not so simple as Caesar cipher or similar ones.

But modern cryptography can be dated from 1952, when the National Security Agency was established and this organization played a key role during the Cold War. The most famous work of NSA is their research based on “Feistel ciphers” (according to Dr. Horst Feistel who establish this cryptographic concept) and published as FIPS PUB-46, but it’s more known under the name DES (see chapter 7.10.4).

7.2.2.1. Milestones in cryptography

Year

Event

1379

Compilation of first European manual on cryptography by Gabriele de Lavinde of Pharma.

1466

First cipher disk was described by Leon Battista Alberti.

1562

A French diplomat Blaise de Vigenère invented special matrix 26x26 called “Vigenere square”.

1854

Charles Babbage developed the method of statistical analysis that had been sucessfuly used to decrypt messages encrypted by Vigenere square.

1918

German engineer Arthur Scherbius invented Enigma.

1930

Japanese used the first rotor machine called “RED”.

1939

Japanese introduced a new cipher machine with code name “PURPLE”.

1943

German’s ENIGMA rotor setting could be rapidly found by “Bomba” machines and cipher texts could be decrypted.

1952

NSA was established.

1976

Diffie and Hellman published famous “New directions in cryptography”, as the beginning of asymmetric cryptography.

http://www.cs.rutgers.edu/~tdnguyen/classes/cs671/presentations/Arvind-NEWDIRS.pdf

1977

DES (Data Encryption Standard) was adopted.

1977

Ron Rivest, Adi Shamir and Leonard Adleman publish their proposal on public key cryptography concept known today as RSA and based on proposal from Diffie and Hellman.

7.3. PKCS

With development of cryptography methods software companies realized the importance of standards to define how to deal with data in secure and standard manner. Sun Microsystem, Microsoft, Applet and others joined this process in RSA and together they defined PKCS standards (Public Key Cryptography Standards).

For application programmers working with any cryptographical functions it’s important to known them because they’re referred in any crypto-documentation and are essential terms. That is why here are listed active PKCS standards with basic introduction (but more can be found on RSA website).

 

Standard

Description

PKCS#1

The RSA encryption standard. Defines mechanisms for encrypting and signing data using RSA system.

PKCS#3

The Diffie-Hellman key agreement standard. It defines Diffie-Hellman key agreement protocol.

PKCS#5

The password-based encryption standard (PBE).It defines a method to generate secret key on a password.

PKCS#6

The extended certificate syntax standard. It’s going to be exchange in favour of X509v3.

PKCS#7

The cryptographic message standard. It defines syntax of messages on which cryptography were used.

PKCS#8

The private key information syntax standard. It defines how to store private key information.

PKCS#9

It defines a selected attribute types for use with other PKCS.

PKCS#10

The certification request syntax standard. It defines syntax of certification requests.

PKCS#11

The cryptographic token interface standard. It defines technology independent programming interface for crypto devices as smartcards.

PKCS#12

The personal information exchange syntax standard. It defines a portable format for storage and transportation of user private keys & certificates etc.

PKCS#13

The elliptic curve cryptography standard. It defines mechanism how to encrypt and sign data using ECC.

PKCS#14

The pseudo random number generation. It defines mechanism of pseudorandom number generation process.

PKCS#15

The cryptographic token information format standard. It defines standard for the format of cryptographic credentials stored on cryptographic tokes.

7.4. CMV (Cryptographic Module validation)

Cryptographical algorithms are studied on mathematical basis but their implementation is the same important. If alrgorithms are not properly implemented than they are opened to attacks. That is why NIST (National Institute of Standards and Technology) has started program CMV which allows software vendors to demonstrate that they comply with the security standards and their implementations are certified as trustworthy (more details about CMV program can be found here: http://csrc.nist.gov/cryptval/).

This is very important for programmers because they have to prove their products are certified if they want to sell to the government or army.

By now there are two types of certification process when FIPS 140 define a framework and methodology for cryptographic standards.

 

 

Comparition of both models can be found here: http://csrc.nist.gov/publications/nistpubs/800-29/sp800-29.pdf.

7.4.1. Microsoft FIPS 140 certification

Microsoft is keen on FIPS certification because they are required by security agencies and governments (not just in USA) as FIPSs are becoming “de-facto” standard for implementation of cryptographic features.

More up-to-date details about certified Microsoft products are published on Microsoft’s website (http://www.microsoft.com/technet/security/topics/issues/fipseval.mspx).

7.4.2. .NET classes and FIPS 140

Only those classes are FIPS 140 certified (they are wrappers around CSP, primary CryptoAPI with FIPS 140 certification):

 

 

So far managed .NET crypto classes are not certified and it seems there are no plans to do it in the future. This is not good for those who develop enterprise applications for government and army. The only solution is to use .NET classes provided by thirt party companies other then Microsoft like:

 

7.5. Cryptography in .NET

Cryptography in .NET environment is based on CryptoAPI provided by Windows. But this doesn’t mean that .NET layer would be just a wrapper around this security feature in Windows. .NET’s namespace System.Security.Cryptography brings many new concepts and approaches to working with cryptography and other security related principles. There’re three primary characteristics:

7.6. Configuring .NET cryptography

Cryptographic namespaces in .NET can use XML configuration to setup the environment to work with appropriate classes and their implementations. Configuration is usually stored in machine.config in this way:

 

<configuration>

      <mscorlib>

            <cryptographySettings>

 

            ..........

 

            </cryptographySettings>

      </mscorlib>

</configuration>

 

Typically there can be setup mapping for Create methods of abstact classes.

This is shown in following sample configuration section:

 

7.7. Win32 Security API and .NET

GotDotNet provides excellent wrapping classes for security features in Windows API. The library can be obtained from http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=e6098575-dda0-48b8-9abf-e0705af065d9 and it is referred by many samples here.

7.8. Random number generators

7.8.1. Generating random values

Namespaces:

using System;

using System.Text;

using System.Security.Cryptography;

 

Code:

static void Main(string[] args)