EaseFilter Demo Project
DigitalRightsManagement.cs
Go to the documentation of this file.
1 //
3 // (C) Copyright 2011 EaseFilter Technologies Inc.
4 // All Rights Reserved
5 //
6 // This software is part of a licensed software product and may
7 // only be used or copied in accordance with the terms of that license.
8 //
10 
11 using System;
12 using System.Collections.Generic;
13 using System.Text;
14 using System.IO;
15 using Microsoft.Win32.SafeHandles;
16 using System.Runtime.InteropServices;
17 using System.Security.Principal;
18 using System.Threading;
19 using System.Diagnostics;
20 using System.Management;
21 using System.Collections;
22 using System.Windows.Forms;
23 
25 
26 namespace SecureAgent
27 {
28  public class CacheUserAccessInfo
29  {
30  public string index = string.Empty;
31  public bool accessStatus = false;
32  public DateTime lastAccessTime = DateTime.MinValue;
33  public string iv = string.Empty;
34  public string key = string.Empty;
35  public AutoResetEvent syncEvent = new AutoResetEvent(true);
36 
37  }
38 
39  public class DRM
40  {
41  Dictionary<string, CacheUserAccessInfo> userAccessCache = new Dictionary<string, CacheUserAccessInfo>();
42  int cacheTimeOutInSeconds = 120;
43  System.Timers.Timer deleteCachedItemTimer = new System.Timers.Timer();
44 
45  public DRM()
46  {
47  deleteCachedItemTimer.Interval = cacheTimeOutInSeconds * 1000 / 4; //millisecond
48  deleteCachedItemTimer.Start();
49  deleteCachedItemTimer.Enabled = true;
50  deleteCachedItemTimer.Elapsed += new System.Timers.ElapsedEventHandler(deleteCachedItemTimer_Elapsed);
51  }
52 
53  private bool GetDRPolicyDataFromDataBuffer(Byte[] drDataBuffer, uint drBufferLength, ref DRPolicyData drPolicyData, ref string lastError)
54  {
55  Boolean retVal = false;
56 
57  try
58  {
59 
60  MemoryStream ms = new MemoryStream(drDataBuffer);
61  BinaryReader br = new BinaryReader(ms);
62 
63  drPolicyData.AESVerificationKey = br.ReadUInt32();
64 
65  if (FilterAPI.AES_TAG_KEY != drPolicyData.AESVerificationKey)
66  {
67  lastError = "The DRPolicyData buffer was corrupted.";
68  return false;
69  }
70 
71  drPolicyData.AESFlags = (AESFlags)br.ReadUInt32();
72  drPolicyData.IVLength = br.ReadUInt32();
73  drPolicyData.IV = br.ReadBytes(16);
74  drPolicyData.EncryptionKeyLength = br.ReadUInt32();
75  drPolicyData.EncryptionKey = br.ReadBytes(32);
76  drPolicyData.CreationTime = br.ReadInt64();
77  drPolicyData.ExpireTime = br.ReadInt64();
78  drPolicyData.AccessFlags = br.ReadUInt32();
79  drPolicyData.FileSize = br.ReadInt64();
80 
81  drPolicyData.LengthOfIncludeProcessNames = br.ReadUInt32();
82  drPolicyData.OffsetOfIncludeProcessNames = br.ReadUInt32();
83  drPolicyData.LengthOfExcludeProcessNames = br.ReadUInt32();
84  drPolicyData.OffsetOfExcludeProcessNames = br.ReadUInt32();
85  drPolicyData.LengthOfIncludeUserNames = br.ReadUInt32();
86  drPolicyData.OffsetOfIncludeUserNames = br.ReadUInt32();
87  drPolicyData.LengthOfExcludeUserNames = br.ReadUInt32();
88  drPolicyData.OffsetOfExcludeUserNames = br.ReadUInt32();
89  drPolicyData.LengthOfAccountName = br.ReadUInt32();
90  drPolicyData.OffsetOfAccountName = br.ReadUInt32();
91  drPolicyData.LengthOfComputerIds = br.ReadUInt32();
92  drPolicyData.OffsetOfComputerIds = br.ReadUInt32();
93  drPolicyData.LengthOfUserPassword = br.ReadUInt32();
94  drPolicyData.OffsetOfUserPassword = br.ReadUInt32();
95 
96  if (drPolicyData.LengthOfIncludeProcessNames > 0 && drPolicyData.OffsetOfIncludeProcessNames > 0)
97  {
98  ms.Position = drPolicyData.OffsetOfIncludeProcessNames;
99  byte[] buffer = br.ReadBytes((int)drPolicyData.LengthOfIncludeProcessNames);
100  drPolicyData.IncludeProcessNames = UnicodeEncoding.Unicode.GetString(buffer);
101  }
102 
103  if (drPolicyData.LengthOfExcludeProcessNames > 0 && drPolicyData.OffsetOfExcludeProcessNames > 0)
104  {
105  ms.Position = drPolicyData.OffsetOfExcludeProcessNames;
106  byte[] buffer = br.ReadBytes((int)drPolicyData.LengthOfExcludeProcessNames);
107  drPolicyData.ExcludeProcessNames = UnicodeEncoding.Unicode.GetString(buffer);
108  }
109 
110  if (drPolicyData.LengthOfIncludeUserNames > 0 && drPolicyData.OffsetOfIncludeUserNames > 0)
111  {
112  ms.Position = drPolicyData.OffsetOfIncludeUserNames;
113  byte[] buffer = br.ReadBytes((int)drPolicyData.LengthOfIncludeUserNames);
114  drPolicyData.IncludeUserNames = UnicodeEncoding.Unicode.GetString(buffer);
115  }
116 
117  if (drPolicyData.LengthOfExcludeUserNames > 0 && drPolicyData.OffsetOfExcludeUserNames > 0)
118  {
119  ms.Position = drPolicyData.OffsetOfExcludeUserNames;
120  byte[] buffer = br.ReadBytes((int)drPolicyData.LengthOfExcludeUserNames);
121  drPolicyData.ExcludeUserNames = UnicodeEncoding.Unicode.GetString(buffer);
122  }
123 
124  if (drPolicyData.LengthOfAccountName > 0 && drPolicyData.OffsetOfAccountName > 0)
125  {
126  ms.Position = drPolicyData.OffsetOfAccountName;
127  byte[] buffer = br.ReadBytes((int)drPolicyData.LengthOfAccountName);
128  drPolicyData.AccountName = UnicodeEncoding.Unicode.GetString(buffer);
129  }
130 
131  if (drPolicyData.LengthOfComputerIds > 0 && drPolicyData.OffsetOfComputerIds > 0)
132  {
133  ms.Position = drPolicyData.OffsetOfComputerIds;
134  byte[] buffer = br.ReadBytes((int)drPolicyData.LengthOfComputerIds);
135  drPolicyData.ComputerIds = UnicodeEncoding.Unicode.GetString(buffer);
136  }
137 
138  if (drPolicyData.LengthOfUserPassword > 0 && drPolicyData.OffsetOfUserPassword > 0)
139  {
140  ms.Position = drPolicyData.OffsetOfUserPassword;
141  byte[] buffer = br.ReadBytes((int)drPolicyData.LengthOfUserPassword);
142  drPolicyData.UserPassword = UnicodeEncoding.Unicode.GetString(buffer);
143  }
144 
145  retVal = true;
146 
147  }
148  catch (Exception ex)
149  {
150  retVal = false;
151  lastError = "Get DRPolicyData failed with error " + ex.Message;
152  }
153 
154  return retVal;
155  }
156 
157  private bool GetAccessPermissionFromServer(FilterAPI.MessageSendData messageSend,
158  DRPolicyData drPolicyData,
159  string userName,
160  string processName,
161  string userPassword,
162  ref CacheUserAccessInfo cacheUserAccessInfo)
163  {
164  Boolean retVal = true;
165  string fileName = messageSend.FileName;
166  string lastError = string.Empty;
167 
168  try
169  {
170  UserInfo userInfo = new UserInfo();
171  string keyStr = string.Empty;
172  string ivStr = string.Empty;
173 
174  userInfo.FileName = Path.GetFileName(messageSend.FileName) + DigitalRightControl.SECURE_SHARE_FILE_EXTENSION;
175  userInfo.AccountName = drPolicyData.AccountName;
176  userInfo.ProcessName = processName;
177  userInfo.UserName = userName;
178  userInfo.UserPassword = userPassword;
179  userInfo.CreationTime = drPolicyData.CreationTime;
180 
181  byte[] computerId = new byte[52];
182  uint computerIdLength = (uint)computerId.Length;
183  IntPtr computerIdPtr = Marshal.UnsafeAddrOfPinnedArrayElement(computerId, 0);
184  retVal = FilterAPI.GetUniqueComputerId(computerIdPtr, ref computerIdLength);
185 
186  if (!retVal)
187  {
188  string message = "Get computerId failed,return error:" + FilterAPI.GetLastErrorMessage();
189  EventManager.WriteMessage(366, "GetAccessPermissionFromServer", EventLevel.Error, message);
190 
191  return retVal;
192  }
193 
194  Array.Resize(ref computerId, (int)computerIdLength);
195 
196  userInfo.ComputerId = UnicodeEncoding.Unicode.GetString(computerId);
197 
198  string userInfoStr = DigitalRightControl.EncryptObjectToStr<UserInfo>(userInfo);
199 
200  Stopwatch stopWatch = new Stopwatch();
201  stopWatch.Start();
202 
203  //get the encryption key from remote server.
204  retVal = false;// GetFileKey(userInfoStr, ref keyStr, ref ivStr, ref lastError);
205 
206  stopWatch.Stop();
207 
208  if (!retVal)
209  {
210  string message = "Get file " + messageSend.FileName + " permission from server return error:" + lastError;
211  EventManager.WriteMessage(293, "GetAccessPermissionFromServer", EventLevel.Error, message);
212 
213  return retVal;
214  }
215  else
216  {
217  string message = "Get file " + messageSend.FileName + " permission frome server return succeed, spent " + stopWatch.ElapsedMilliseconds + " milliseconds.";
218  EventManager.WriteMessage(208, "GetAccessPermissionFromServer", EventLevel.Verbose, message);
219  }
220 
221  cacheUserAccessInfo.key = keyStr;
222  cacheUserAccessInfo.iv = ivStr;
223 
224  }
225  catch (Exception ex)
226  {
227  EventManager.WriteMessage(286, "GetAccessPermissionFromServer", EventLevel.Error, "Get file " + messageSend.FileName + "permission failed with exception:" + ex.Message);
228  retVal = false;
229  }
230 
231  return retVal;
232 
233  }
234 
235  public bool GetUserPermission(FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply)
236  {
237  Boolean retVal = true;
238  string userPassword = string.Empty;
239  string fileName = messageSend.FileName;
240  string lastError = string.Empty;
241  string processName = string.Empty;
242  string userName = string.Empty;
243  bool isFirstAccess = false;
244  CacheUserAccessInfo cacheUserAccessInfo = new CacheUserAccessInfo();
245 
246  try
247  {
248 
249  FilterAPI.DecodeProcessName(messageSend.ProcessId, out processName);
250  FilterAPI.DecodeUserName(messageSend.Sid, out userName);
251 
252  string index = (userName + "_" + processName + "_" + fileName).ToLower();
253 
254  //cache the same user/process/filename access.
255  lock (userAccessCache)
256  {
257  if (userAccessCache.ContainsKey(index))
258  {
259  cacheUserAccessInfo = userAccessCache[index];
260  EventManager.WriteMessage(446, "GetUserPermission", EventLevel.Verbose, "Thread" + Thread.CurrentThread.ManagedThreadId + ",userInfoKey " + index + " exists in the cache table.");
261  }
262  else
263  {
264  isFirstAccess = true;
265  cacheUserAccessInfo.index = index;
266  cacheUserAccessInfo.lastAccessTime = DateTime.Now;
267  userAccessCache.Add(index, cacheUserAccessInfo);
268  EventManager.WriteMessage(435, "GetUserPermission", EventLevel.Verbose, "Thread" + Thread.CurrentThread.ManagedThreadId + ",add userInfoKey " + index + " to the cache table.");
269  }
270  }
271 
272  //synchronize the same file access.
273  if (!cacheUserAccessInfo.syncEvent.WaitOne(new TimeSpan(0, 0, (int)GlobalConfig.ConnectionTimeOut)))
274  {
275  string info = "User name: " + userName + ",processname:" + processName + ",file name:" + fileName + " wait for permission timeout.";
276  EventManager.WriteMessage(402, "GetUserPermission", EventLevel.Warning, info);
277  }
278 
279  TimeSpan timeSpan = DateTime.Now - cacheUserAccessInfo.lastAccessTime;
280 
281  if (!isFirstAccess && timeSpan.TotalSeconds < cacheTimeOutInSeconds)
282  {
283  //the access was cached, return the last access status.
284  retVal = cacheUserAccessInfo.accessStatus;
285 
286  string info = "thread" + Thread.CurrentThread.ManagedThreadId + ", Cached userInfoKey " + index + " in the cache table,return " + retVal;
287  EventManager.WriteMessage(451, "GetUserPermission", EventLevel.Verbose, info);
288 
289  return retVal;
290  }
291 
292 
293  DRPolicyData drPolicyData = new DRPolicyData();
294  retVal = GetDRPolicyDataFromDataBuffer(messageSend.DataBuffer, messageSend.Length, ref drPolicyData, ref lastError);
295  if (!retVal)
296  {
297  EventManager.WriteMessage(258, "GetUserPermission", EventLevel.Error, "Process encrypted file failed because of error:" + lastError);
298  }
299  else
300  {
301  if ((drPolicyData.AESFlags & AESFlags.Flags_Enabled_Check_User_Password) == AESFlags.Flags_Enabled_Check_User_Password)
302  {
303  string messageInfo = "User name: " + userName + ",processname:" + processName + ",file name:" + fileName + "\n\n Enter password in password windows.";
304  EventManager.WriteMessage(301, "Request user password.", EventLevel.Verbose,messageInfo);
305 
306  UserPasswordForm userPasswordForm = new UserPasswordForm(userName, processName, fileName);
307  userPasswordForm.BringToFront();
308  userPasswordForm.Focus();
309  userPasswordForm.TopMost = true;
310 
311  if (userPasswordForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
312  {
313  userPassword = userPasswordForm.userPassword;
314  }
315  }
316 
317  if ((drPolicyData.AESFlags & AESFlags.Flags_Enabled_Revoke_Access_Control) == AESFlags.Flags_Enabled_Revoke_Access_Control)
318  {
319  retVal = GetAccessPermissionFromServer(messageSend, drPolicyData, userName, processName, userPassword, ref cacheUserAccessInfo);
320  }
321  else
322  {
323  if (drPolicyData.UserPassword.Length > 0)
324  {
325  if (!string.Equals(userPassword, drPolicyData.UserPassword))
326  {
327  retVal = false;
328  }
329  }
330  }
331  }
332 
333  cacheUserAccessInfo.accessStatus = retVal;
334 
335  }
336  catch (Exception ex)
337  {
338  EventManager.WriteMessage(340, "GetUserPermission", EventLevel.Error, "filter callback exception." + ex.Message);
339  retVal = false;
340  }
341  finally
342  {
343  if (!string.IsNullOrEmpty(cacheUserAccessInfo.key))
344  {
345  byte[] encryptKey = Utils.ConvertHexStrToByteArray(cacheUserAccessInfo.key);
346  byte[] encryptIV = Utils.ConvertHexStrToByteArray(cacheUserAccessInfo.iv);
347 
348 
349  //write the iv and key to the reply data buffer with format FilterAPI.AESDataBuffer
350  MemoryStream ms = new MemoryStream(messageReply.DataBuffer);
351  BinaryWriter bw = new BinaryWriter(ms);
352  bw.Write(encryptIV);
353  bw.Write(encryptKey.Length);
354  bw.Write(encryptKey);
355 
356  messageReply.DataBufferLength = (uint)ms.Length;
357  }
358 
359  cacheUserAccessInfo.lastAccessTime = DateTime.Now;
360  cacheUserAccessInfo.syncEvent.Set();
361 
362 
363  }
364 
365  return retVal;
366 
367  }
368 
369  private void deleteCachedItemTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
370  {
371 
372  try
373  {
374  List<string> keysToRemove = new List<string>();
375 
376  foreach (KeyValuePair<string, CacheUserAccessInfo> userItem in userAccessCache)
377  {
378 
379  TimeSpan tsSinceLastAccess = DateTime.Now - userItem.Value.lastAccessTime;
380 
381  if (tsSinceLastAccess.TotalSeconds >= cacheTimeOutInSeconds)
382  {
383  keysToRemove.Add(userItem.Key);
384  }
385  }
386 
387  foreach (string key in keysToRemove)
388  {
389  lock (userAccessCache)
390  {
391  userAccessCache.Remove(key);
392 
393  EventManager.WriteMessage(573, "deleteCachedItemTimer_Elapsed", EventLevel.Verbose, "Delete cached item " + key);
394  }
395  }
396  }
397  catch (System.Exception ex)
398  {
399  EventManager.WriteMessage(46, "deleteCachedItemTimer_Elapsed", EventLevel.Error, "Delete cached item failed with error:" + ex.Message);
400  }
401 
402  }
403  }
404 }
WCHAR * userName
Definition: FilterAPI.h:604
enum _AESFlags AESFlags
string UserName
the user name who access the file.
string FileName
the encrypted file which was accessed.
string UserPassword
the password of the user input.
bool GetUserPermission(FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply)
WCHAR * processName
Definition: FilterAPI.h:596
static byte [] ConvertHexStrToByteArray(string hexString)
Definition: Utils.cs:185
string ComputerId
the computer information which access the file.
string AccountName
the owner account name
long CreationTime
the creation time of the file which was accessed.
This the DR data which will be embedded to the encyrpted file if the revoke access control flag is no...
string ProcessName
the process name which access the file.

Social Network


Services Overview

Architect, implement and test file system filter drivers for a wide range of functionality. We can offer several levels of assistance to meet your specific.

Contact Us

You are welcome to contact us for salse or partnership.

Sales: sales@easefilter.com
Support: support@easefilter.com
Info: info@easefilter.com