Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / security / securestring.cs
1 // <OWNER>Microsoft</OWNER>
2 namespace System.Security {
3     using System.Security.Cryptography;
4     using System.Runtime.InteropServices;
5 #if FEATURE_CORRUPTING_EXCEPTIONS
6     using System.Runtime.ExceptionServices;
7 #endif // FEATURE_CORRUPTING_EXCEPTIONS
8     using System.Text;
9     using Microsoft.Win32;
10     using System.Runtime.CompilerServices;
11     using System.Security.Permissions;
12     using System.Runtime.ConstrainedExecution;
13     using System.Runtime.Versioning;
14     using Microsoft.Win32.SafeHandles;
15     using System.Diagnostics.Contracts;
16
17     public sealed class SecureString: IDisposable {
18         [System.Security.SecurityCritical] // auto-generated
19         private SafeBSTRHandle m_buffer; 
20         [ContractPublicPropertyName("Length")]
21         private int       m_length;
22         private bool     m_readOnly;
23         private bool     m_encrypted; 
24         
25         static bool supportedOnCurrentPlatform = EncryptionSupported();
26
27         const int BlockSize = (int)Win32Native.CRYPTPROTECTMEMORY_BLOCK_SIZE /2;  // a char is two bytes
28         const int MaxLength = 65536;
29         const uint ProtectionScope = Win32Native.CRYPTPROTECTMEMORY_SAME_PROCESS;
30                 
31         [System.Security.SecuritySafeCritical]  // auto-generated
32         static SecureString()
33         {
34         }
35
36         [System.Security.SecurityCritical]  // auto-generated
37         unsafe static bool EncryptionSupported() {
38             // check if the enrypt/decrypt function is supported on current OS
39             bool supported = true;                        
40             try {
41                 Win32Native.SystemFunction041(
42                     SafeBSTRHandle.Allocate(null , (int)Win32Native.CRYPTPROTECTMEMORY_BLOCK_SIZE),
43                     Win32Native.CRYPTPROTECTMEMORY_BLOCK_SIZE, 
44                     Win32Native.CRYPTPROTECTMEMORY_SAME_PROCESS);
45             }
46             catch (EntryPointNotFoundException) {
47                 supported = false;
48             }            
49             return supported;
50         }
51         
52         [System.Security.SecurityCritical]  // auto-generated
53         internal SecureString(SecureString str) {
54             AllocateBuffer(str.BufferLength); 
55             SafeBSTRHandle.Copy(str.m_buffer, this.m_buffer);
56             m_length = str.m_length;
57             m_encrypted = str.m_encrypted;
58         }
59
60         
61         [System.Security.SecuritySafeCritical]  // auto-generated
62         public SecureString() {
63             CheckSupportedOnCurrentPlatform();            
64             
65             // allocate the minimum block size for calling protectMemory
66             AllocateBuffer(BlockSize);  
67             m_length = 0;
68         }
69          
70
71         [System.Security.SecurityCritical]  // auto-generated
72 #if FEATURE_CORRUPTING_EXCEPTIONS
73         [HandleProcessCorruptedStateExceptions] // 
74 #endif // FEATURE_CORRUPTING_EXCEPTIONS
75         private unsafe void InitializeSecureString(char* value, int length)
76         {
77             CheckSupportedOnCurrentPlatform();
78
79             AllocateBuffer(length);
80             m_length = length;
81
82             byte* bufferPtr = null;
83             RuntimeHelpers.PrepareConstrainedRegions();
84             try
85             {
86                 m_buffer.AcquirePointer(ref bufferPtr);
87                 Buffer.Memcpy(bufferPtr, (byte*)value, length * 2);
88             }
89             catch (Exception) {
90                 ProtectMemory();
91                 throw;
92             }
93             finally
94             {
95                 if (bufferPtr != null)
96                     m_buffer.ReleasePointer();
97             }
98
99             ProtectMemory();
100         }
101
102         [System.Security.SecurityCritical]  // auto-generated
103         [CLSCompliant(false)]
104         public unsafe SecureString(char* value, int length) {
105             if( value == null) {
106                 throw new ArgumentNullException("value");
107             }
108
109             if( length < 0) {
110                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
111             }
112
113             if( length > MaxLength) {
114                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Length"));
115             }
116             Contract.EndContractBlock();
117
118             // Refactored since HandleProcessCorruptedStateExceptionsAttribute applies to methods only (yet).
119             InitializeSecureString(value, length);
120         }
121   
122         public int Length { 
123             [System.Security.SecuritySafeCritical]  // auto-generated
124             [MethodImplAttribute(MethodImplOptions.Synchronized)]
125             get  { 
126                 EnsureNotDisposed();
127                 return m_length;
128             }
129         }
130
131         [System.Security.SecuritySafeCritical]  // auto-generated
132         [MethodImplAttribute(MethodImplOptions.Synchronized)]
133 #if FEATURE_CORRUPTING_EXCEPTIONS
134         [HandleProcessCorruptedStateExceptions] // 
135 #endif // FEATURE_CORRUPTING_EXCEPTIONS
136         public void AppendChar(char c) {
137             EnsureNotDisposed();
138             EnsureNotReadOnly();
139
140             EnsureCapacity(m_length + 1);
141
142             RuntimeHelpers.PrepareConstrainedRegions();
143             try {
144                 UnProtectMemory();            
145                 m_buffer.Write<char>((uint)m_length * sizeof(char), c);
146                 m_length++;
147             }
148             catch (Exception) {
149                 ProtectMemory();
150                 throw;
151             }
152             finally {
153                 ProtectMemory();            
154             }
155         }
156
157         // clears the current contents. Only available if writable
158         [System.Security.SecuritySafeCritical]  // auto-generated
159         [MethodImplAttribute(MethodImplOptions.Synchronized)]
160         public void Clear() {
161             EnsureNotDisposed();
162             EnsureNotReadOnly();
163
164             m_length = 0;
165             m_buffer.ClearBuffer();
166             m_encrypted = false;
167         }
168                 
169         // Do a deep-copy of the SecureString 
170         [System.Security.SecuritySafeCritical]  // auto-generated
171         [MethodImplAttribute(MethodImplOptions.Synchronized)]
172         public SecureString Copy() {
173             EnsureNotDisposed();
174             return new SecureString(this);
175         }
176
177         [System.Security.SecuritySafeCritical]  // auto-generated
178         [MethodImplAttribute(MethodImplOptions.Synchronized)]
179         public void Dispose() {
180             if(m_buffer != null && !m_buffer.IsInvalid) {
181                 m_buffer.Close();
182                 m_buffer = null;   
183             }            
184         }
185
186         [System.Security.SecuritySafeCritical]  // auto-generated
187         [MethodImplAttribute(MethodImplOptions.Synchronized)]
188 #if FEATURE_CORRUPTING_EXCEPTIONS
189         [HandleProcessCorruptedStateExceptions] // 
190 #endif // FEATURE_CORRUPTING_EXCEPTIONS
191         public void InsertAt( int index, char c ) {
192             if( index < 0 || index > m_length) {
193                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexString"));
194             }
195             Contract.EndContractBlock();
196
197             EnsureNotDisposed();
198             EnsureNotReadOnly();
199
200             EnsureCapacity(m_length + 1);
201
202             unsafe {
203                 byte* bufferPtr = null;
204                 RuntimeHelpers.PrepareConstrainedRegions();
205                 try {
206                     UnProtectMemory();
207                     m_buffer.AcquirePointer(ref bufferPtr);
208                     char* pBuffer = (char*)bufferPtr;
209
210                     for (int i = m_length; i > index; i--) {
211                         pBuffer[i] = pBuffer[i - 1];
212                     }
213                     pBuffer[index] = c;
214                     ++m_length;
215                 }
216                 catch (Exception) {
217                     ProtectMemory();
218                     throw;
219                 }
220                 finally {
221                     ProtectMemory();
222                     if (bufferPtr != null)
223                         m_buffer.ReleasePointer();
224                 }
225             }
226         }
227
228         [System.Security.SecuritySafeCritical]  // auto-generated
229         [MethodImplAttribute(MethodImplOptions.Synchronized)]
230         public bool IsReadOnly() {
231             EnsureNotDisposed();
232             return m_readOnly; 
233         }
234
235         [System.Security.SecuritySafeCritical]  // auto-generated
236         [MethodImplAttribute(MethodImplOptions.Synchronized)]
237         public void MakeReadOnly() {
238             EnsureNotDisposed();
239             m_readOnly = true;
240         }
241
242         [System.Security.SecuritySafeCritical]  // auto-generated
243         [MethodImplAttribute(MethodImplOptions.Synchronized)]
244 #if FEATURE_CORRUPTING_EXCEPTIONS
245         [HandleProcessCorruptedStateExceptions] // 
246 #endif // FEATURE_CORRUPTING_EXCEPTIONS
247         public void RemoveAt( int index ) {
248             EnsureNotDisposed();
249             EnsureNotReadOnly();
250
251             if( index < 0 || index >= m_length) {
252                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexString"));
253             }
254
255             unsafe
256             {
257                 byte* bufferPtr = null;
258                 RuntimeHelpers.PrepareConstrainedRegions();
259                 try
260                 {
261                     UnProtectMemory();
262                     m_buffer.AcquirePointer(ref bufferPtr);
263                     char* pBuffer = (char*)bufferPtr;
264
265                     for (int i = index; i < m_length - 1; i++)
266                     {
267                         pBuffer[i] = pBuffer[i + 1];
268                     }
269                     pBuffer[--m_length] = (char)0;
270                 }
271                 catch (Exception) {
272                     ProtectMemory();
273                     throw;
274                 }
275                 finally
276                 {
277                     ProtectMemory();
278                     if (bufferPtr != null)
279                         m_buffer.ReleasePointer();
280                 }
281             }
282         }
283
284         [System.Security.SecuritySafeCritical]  // auto-generated
285         [MethodImplAttribute(MethodImplOptions.Synchronized)]
286 #if FEATURE_CORRUPTING_EXCEPTIONS
287         [HandleProcessCorruptedStateExceptions] // 
288 #endif // FEATURE_CORRUPTING_EXCEPTIONS
289         public void SetAt( int index, char c ) {
290             if( index < 0 || index >= m_length) {
291                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexString"));
292             }
293             Contract.EndContractBlock();
294             Contract.Assert(index <= Int32.MaxValue / sizeof(char));
295
296             EnsureNotDisposed();
297             EnsureNotReadOnly();
298
299             RuntimeHelpers.PrepareConstrainedRegions();
300             try {
301                 UnProtectMemory();            
302                 m_buffer.Write<char>((uint)index * sizeof(char), c);
303             }
304             catch (Exception) {
305                 ProtectMemory();
306                 throw;
307             }
308             finally {
309                 ProtectMemory();            
310             }
311         }
312
313         private int BufferLength {
314             [System.Security.SecurityCritical]  // auto-generated
315             get {
316                 Contract.Assert(m_buffer != null, "Buffer is not initialized!");   
317                 return m_buffer.Length;
318             }
319         }
320
321         [System.Security.SecurityCritical]  // auto-generated
322         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
323         private void AllocateBuffer(int size) {
324             uint alignedSize = GetAlignedSize(size);
325
326             m_buffer = SafeBSTRHandle.Allocate(null, alignedSize);
327             if (m_buffer.IsInvalid) {
328                 throw new OutOfMemoryException();
329             }
330         }
331         
332         private void CheckSupportedOnCurrentPlatform() {
333             if( !supportedOnCurrentPlatform) {
334                 throw new NotSupportedException(Environment.GetResourceString("Arg_PlatformSecureString"));
335             }                            
336             Contract.EndContractBlock();
337         }
338
339         [System.Security.SecurityCritical]  // auto-generated
340         private void EnsureCapacity(int capacity) {            
341             if( capacity > MaxLength) {
342                 throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_Capacity"));
343             }
344             Contract.EndContractBlock();
345
346             if( capacity <= m_buffer.Length) {
347                 return;
348             }
349
350             SafeBSTRHandle newBuffer = SafeBSTRHandle.Allocate(null, GetAlignedSize(capacity));
351
352             if (newBuffer.IsInvalid) {
353                 throw new OutOfMemoryException();
354             }                
355
356             SafeBSTRHandle.Copy(m_buffer, newBuffer);
357             m_buffer.Close();
358             m_buffer = newBuffer;                
359         }
360
361         [System.Security.SecurityCritical]  // auto-generated
362         private void EnsureNotDisposed() {
363             if( m_buffer == null) {
364                 throw new ObjectDisposedException(null);
365             }
366             Contract.EndContractBlock();
367         }
368
369         private void EnsureNotReadOnly() {
370             if( m_readOnly) {
371                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
372             }
373             Contract.EndContractBlock();
374         }
375
376         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
377         private static uint GetAlignedSize( int size) {
378             Contract.Assert(size >= 0, "size must be non-negative");
379
380             uint alignedSize = ((uint)size / BlockSize) * BlockSize;
381             if( (size % BlockSize != 0) || size == 0) {  // if size is 0, set allocated size to blocksize
382                 alignedSize += BlockSize;
383             }
384             return alignedSize;
385         }
386
387         [System.Security.SecurityCritical]  // auto-generated
388         private unsafe int GetAnsiByteCount() {
389             const uint CP_ACP               = 0;
390             const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
391
392             uint flgs = WC_NO_BEST_FIT_CHARS;
393             uint DefaultCharUsed = (uint)'?';            
394             
395             byte* bufferPtr = null;
396             RuntimeHelpers.PrepareConstrainedRegions();
397             try {
398                 m_buffer.AcquirePointer(ref bufferPtr);
399
400                 return Win32Native.WideCharToMultiByte(
401                     CP_ACP,
402                     flgs,
403                     (char*) bufferPtr,
404                     m_length,
405                     null,
406                     0,
407                     IntPtr.Zero,
408                     new IntPtr((void*)&DefaultCharUsed));
409             }
410             finally {
411                 if (bufferPtr != null)
412                     m_buffer.ReleasePointer();
413             }
414         }
415
416         [System.Security.SecurityCritical]  // auto-generated
417         private unsafe void GetAnsiBytes( byte * ansiStrPtr, int byteCount) {
418             const uint CP_ACP               = 0;
419             const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
420
421             uint flgs = WC_NO_BEST_FIT_CHARS;
422             uint DefaultCharUsed = (uint)'?';
423
424             byte* bufferPtr = null;
425             RuntimeHelpers.PrepareConstrainedRegions();
426             try {
427                 m_buffer.AcquirePointer(ref bufferPtr);
428
429                 Win32Native.WideCharToMultiByte(
430                     CP_ACP,
431                     flgs,
432                     (char*) bufferPtr,
433                     m_length,
434                     ansiStrPtr,
435                     byteCount - 1,
436                     IntPtr.Zero,
437                     new IntPtr((void*)&DefaultCharUsed));
438
439                 *(ansiStrPtr + byteCount - 1) = (byte)0;
440             }
441             finally {
442                 if (bufferPtr != null)
443                     m_buffer.ReleasePointer();
444             }
445         }
446
447         [System.Security.SecurityCritical]  // auto-generated
448         [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
449         private void ProtectMemory() {            
450             Contract.Assert(!m_buffer.IsInvalid && m_buffer.Length != 0, "Invalid buffer!");
451             Contract.Assert(m_buffer.Length % BlockSize == 0, "buffer length must be multiple of blocksize!");
452
453             if( m_length == 0 || m_encrypted) {
454                 return;
455             }
456
457             RuntimeHelpers.PrepareConstrainedRegions();
458             try {
459             }
460             finally {
461                 // RtlEncryptMemory return an NTSTATUS
462                 int status = Win32Native.SystemFunction040(m_buffer, (uint)m_buffer.Length * 2, ProtectionScope);
463                 if (status < 0)  { // non-negative numbers indicate success
464 #if FEATURE_CORECLR
465                     throw new CryptographicException(Win32Native.RtlNtStatusToDosError(status));
466 #else
467                     throw new CryptographicException(Win32Native.LsaNtStatusToWinError(status));
468 #endif
469                 }
470                 m_encrypted = true;
471             }            
472         }
473         
474         [System.Security.SecurityCritical]  // auto-generated
475         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
476         [MethodImplAttribute(MethodImplOptions.Synchronized)]
477 #if FEATURE_CORRUPTING_EXCEPTIONS
478         [HandleProcessCorruptedStateExceptions] // 
479 #endif // FEATURE_CORRUPTING_EXCEPTIONS
480         internal unsafe IntPtr ToBSTR() {
481             EnsureNotDisposed();
482             int length = m_length;        
483             IntPtr ptr = IntPtr.Zero;
484             IntPtr result = IntPtr.Zero;
485             byte* bufferPtr = null;
486
487             RuntimeHelpers.PrepareConstrainedRegions();
488             try {            
489                 RuntimeHelpers.PrepareConstrainedRegions();            
490                 try {
491                 }
492                 finally {
493                     ptr = Win32Native.SysAllocStringLen(null, length);
494                 }
495                 
496                 if (ptr == IntPtr.Zero) {
497                     throw new OutOfMemoryException();
498                 }
499                 
500                 UnProtectMemory();
501                 m_buffer.AcquirePointer(ref bufferPtr);
502                 Buffer.Memcpy((byte*) ptr.ToPointer(), bufferPtr, length *2); 
503                 result = ptr;
504             }
505             catch (Exception) {
506                 ProtectMemory();
507                 throw;
508             }
509             finally {                
510                 ProtectMemory();                
511                 if( result == IntPtr.Zero) { 
512                     // If we failed for any reason, free the new buffer
513                     if (ptr != IntPtr.Zero) {
514                         Win32Native.ZeroMemory(ptr, (UIntPtr)(length * 2));
515                         Win32Native.SysFreeString(ptr);
516                     }                    
517                 }
518                 if (bufferPtr != null)
519                     m_buffer.ReleasePointer();
520             }
521             return result;        
522         }
523
524         [System.Security.SecurityCritical]  // auto-generated
525         [MethodImplAttribute(MethodImplOptions.Synchronized)]
526 #if FEATURE_CORRUPTING_EXCEPTIONS
527         [HandleProcessCorruptedStateExceptions] // 
528 #endif // FEATURE_CORRUPTING_EXCEPTIONS
529         internal unsafe IntPtr ToUniStr(bool allocateFromHeap) {
530             EnsureNotDisposed();
531             int length = m_length;
532             IntPtr ptr = IntPtr.Zero;
533             IntPtr result = IntPtr.Zero;
534             byte* bufferPtr = null;
535
536             RuntimeHelpers.PrepareConstrainedRegions();            
537             try {
538                 RuntimeHelpers.PrepareConstrainedRegions();            
539                 try {
540                 }
541                 finally {
542                     if( allocateFromHeap) {
543                         ptr = Marshal.AllocHGlobal((length + 1) * 2);
544                     }
545                     else {
546                         ptr = Marshal.AllocCoTaskMem((length + 1) * 2);
547                     }
548                 }
549
550                 if (ptr == IntPtr.Zero) {
551                     throw new OutOfMemoryException();
552                 }
553             
554                 UnProtectMemory();
555                 m_buffer.AcquirePointer(ref bufferPtr);
556                 Buffer.Memcpy((byte*) ptr.ToPointer(), bufferPtr, length *2); 
557                 char * endptr = (char *) ptr.ToPointer();
558                 *(endptr + length) = '\0';
559                 result = ptr;
560             }
561             catch (Exception) {
562                 ProtectMemory();
563                 throw;
564             }
565             finally {
566                 ProtectMemory();
567
568                 if( result == IntPtr.Zero) { 
569                     // If we failed for any reason, free the new buffer
570                     if (ptr != IntPtr.Zero) {
571                         Win32Native.ZeroMemory(ptr, (UIntPtr)(length * 2));
572                         if( allocateFromHeap) {                                                    
573                             Marshal.FreeHGlobal(ptr);
574                         }
575                         else {
576                             Marshal.FreeCoTaskMem(ptr);
577                         }
578                     }                    
579                 }
580
581                 if (bufferPtr != null)
582                     m_buffer.ReleasePointer();
583             }
584             return result;
585         }
586
587         [System.Security.SecurityCritical]  // auto-generated
588         [MethodImplAttribute(MethodImplOptions.Synchronized)]
589 #if FEATURE_CORRUPTING_EXCEPTIONS
590         [HandleProcessCorruptedStateExceptions] // 
591 #endif // FEATURE_CORRUPTING_EXCEPTIONS
592         internal unsafe IntPtr ToAnsiStr(bool allocateFromHeap) {
593             EnsureNotDisposed();
594             
595             IntPtr ptr = IntPtr.Zero;
596             IntPtr result = IntPtr.Zero;          
597             int byteCount = 0;
598             RuntimeHelpers.PrepareConstrainedRegions();                        
599             try {
600                 // GetAnsiByteCount uses the string data, so the calculation must happen after we are decrypted.
601                 UnProtectMemory();
602                 
603                 // allocating an extra char for terminating zero
604                 byteCount = GetAnsiByteCount() + 1; 
605                 
606                 RuntimeHelpers.PrepareConstrainedRegions();
607                 try {
608                 }
609                 finally {
610                     if( allocateFromHeap) {
611                         ptr = Marshal.AllocHGlobal(byteCount);
612                     }
613                     else {
614                         ptr = Marshal.AllocCoTaskMem(byteCount);
615                    }                    
616                 }
617
618                 if (ptr == IntPtr.Zero) {
619                     throw new OutOfMemoryException();
620                 }
621                 
622                 GetAnsiBytes((byte *)ptr.ToPointer(), byteCount);
623                 result = ptr;                
624             }
625             catch (Exception) {
626                 ProtectMemory();
627                 throw;
628             }
629             finally {
630                 ProtectMemory();
631                 if( result == IntPtr.Zero) { 
632                     // If we failed for any reason, free the new buffer
633                     if (ptr != IntPtr.Zero) {
634                         Win32Native.ZeroMemory(ptr, (UIntPtr)byteCount);
635                         if( allocateFromHeap) {                                                    
636                             Marshal.FreeHGlobal(ptr);
637                         }
638                         else {
639                             Marshal.FreeCoTaskMem(ptr);                            
640                         }
641                     }                    
642                 }                
643                 
644             }
645             return result;
646         }
647
648         [System.Security.SecurityCritical]  // auto-generated
649         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
650         private void UnProtectMemory() {
651             Contract.Assert(!m_buffer.IsInvalid && m_buffer.Length != 0, "Invalid buffer!");
652             Contract.Assert(m_buffer.Length % BlockSize == 0, "buffer length must be multiple of blocksize!");
653
654             if( m_length == 0) {
655                 return;
656             }
657             
658             RuntimeHelpers.PrepareConstrainedRegions();
659             try {
660             }
661             finally {
662                 if (m_encrypted) {
663                     // RtlEncryptMemory return an NTSTATUS
664                     int status = Win32Native.SystemFunction041(m_buffer, (uint)m_buffer.Length * 2, ProtectionScope);
665                     if (status < 0)
666                     { // non-negative numbers indicate success
667 #if FEATURE_CORECLR
668                         throw new CryptographicException(Win32Native.RtlNtStatusToDosError(status));
669 #else
670                         throw new CryptographicException(Win32Native.LsaNtStatusToWinError(status));
671 #endif
672                     }
673                     m_encrypted = false;
674                 }
675             }
676         }        
677     }
678
679     [System.Security.SecurityCritical]  // auto-generated
680     [SuppressUnmanagedCodeSecurityAttribute()]
681     internal sealed class SafeBSTRHandle : SafeBuffer {
682         internal SafeBSTRHandle () : base(true) {}
683
684         internal static SafeBSTRHandle Allocate(String src, uint len)
685         {
686             SafeBSTRHandle bstr = SysAllocStringLen(src, len);
687             bstr.Initialize(len * sizeof(char));
688             return bstr;
689         }
690
691         [ResourceExposure(ResourceScope.None)]
692         [DllImport(Win32Native.OLEAUT32, CharSet = CharSet.Unicode)]
693         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]            
694         private static extern SafeBSTRHandle SysAllocStringLen(String src, uint len);  // BSTR
695
696         [System.Security.SecurityCritical]
697         override protected bool ReleaseHandle()
698         {
699             Win32Native.ZeroMemory(handle, (UIntPtr) (Win32Native.SysStringLen(handle) * 2));
700             Win32Native.SysFreeString(handle);
701             return true;
702         }
703
704         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
705         internal unsafe void ClearBuffer() {
706             byte* bufferPtr = null;
707             RuntimeHelpers.PrepareConstrainedRegions();
708             try
709             {
710                 AcquirePointer(ref bufferPtr);
711                 Win32Native.ZeroMemory((IntPtr)bufferPtr, (UIntPtr) (Win32Native.SysStringLen((IntPtr)bufferPtr) * 2));
712             }
713             finally
714             {
715                 if (bufferPtr != null)
716                     ReleasePointer();
717             }
718         }
719
720
721         internal unsafe int Length {
722             get {
723                 return (int) Win32Native.SysStringLen(this);
724             }
725         }
726
727         internal unsafe static void Copy(SafeBSTRHandle source, SafeBSTRHandle target) {
728             byte* sourcePtr = null, targetPtr = null;
729             RuntimeHelpers.PrepareConstrainedRegions();
730             try
731             {
732                 source.AcquirePointer(ref sourcePtr);
733                 target.AcquirePointer(ref targetPtr);
734
735                 Contract.Assert(Win32Native.SysStringLen((IntPtr)targetPtr) >= Win32Native.SysStringLen((IntPtr)sourcePtr), "Target buffer is not large enough!");
736
737                 Buffer.Memcpy(targetPtr, sourcePtr, (int) Win32Native.SysStringLen((IntPtr)sourcePtr) * 2);
738             }
739             finally
740             {
741                 if (sourcePtr != null)
742                     source.ReleasePointer();
743                 if (targetPtr != null)
744                     target.ReleasePointer();
745             }
746         }
747     }
748 }
749