2 // SN.cs: sn clone tool
5 // Sebastien Pouliot (spouliot@motus.com)
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
12 using System.Reflection;
13 using System.Security.Cryptography;
17 using Mono.Security.Cryptography;
19 [assembly: AssemblyTitle("Mono StrongName")]
20 [assembly: AssemblyDescription("StrongName utility for signing assemblies")]
22 namespace Mono.Tools {
26 static private void Header ()
28 Assembly a = Assembly.GetExecutingAssembly ();
29 AssemblyName an = a.GetName ();
31 object [] att = a.GetCustomAttributes (typeof (AssemblyTitleAttribute), false);
32 string title = ((att.Length > 0) ? ((AssemblyTitleAttribute) att [0]).Title : "Mono StrongName");
34 att = a.GetCustomAttributes (typeof (AssemblyCopyrightAttribute), false);
35 string copyright = ((att.Length > 0) ? ((AssemblyCopyrightAttribute) att [0]).Copyright : "");
37 Console.WriteLine ("{0} {1}", title, an.Version.ToString ());
38 Console.WriteLine ("{0}{1}", copyright, Environment.NewLine);
41 static string defaultCSP = null;
44 static bool LoadConfig ()
51 static int SaveConfig ()
57 static byte[] ReadFromFile (string fileName)
60 FileStream fs = File.Open (fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
62 data = new byte [fs.Length];
63 fs.Read (data, 0, data.Length);
71 static void WriteToFile (string fileName, byte[] data)
73 FileStream fs = File.Open (fileName, FileMode.Create, FileAccess.Write);
75 fs.Write (data, 0, data.Length);
82 static void WriteCSVToFile (string fileName, byte[] data, string mask)
84 StreamWriter sw = File.CreateText (fileName);
86 for (int i=0; i < data.Length; i++) {
89 sw.Write (data [i].ToString (mask));
98 static string ToString (byte[] data)
100 StringBuilder sb = new StringBuilder ();
101 for (int i=0; i < data.Length; i++) {
102 if ((i % 39 == 0) && (data.Length > 39))
103 sb.Append (Environment.NewLine);
104 sb.Append (data [i].ToString ("x2"));
106 sb.Append (" !!! TOO LONG !!!");
110 return sb.ToString ();
113 // is assembly signed (or delayed signed) ?
114 static bool IsStrongNamed (Assembly assembly)
116 if (assembly == null)
119 object[] attrs = assembly.GetCustomAttributes (true);
120 foreach (object o in attrs) {
121 if (o is AssemblyKeyFileAttribute)
123 else if (o is AssemblyKeyNameAttribute)
129 static void ReSign (string assemblyName, RSA key)
131 // this doesn't load the assembly (well it unloads it ;)
132 // http://weblogs.asp.net/nunitaddin/posts/9991.aspx
133 AssemblyName an = AssemblyName.GetAssemblyName (assemblyName);
135 Console.WriteLine ("Unable to load assembly: {0}", assemblyName);
139 StrongName sign = new StrongName (key);
140 // try to compare public key
141 bool same = Compare (sign.PublicKey, an.GetPublicKey ());
143 // second chance, try to compare public key token
144 same = Compare (sign.PublicKeyToken, an.GetPublicKeyToken ());
147 if ((same) && (an.Flags == AssemblyNameFlags.PublicKey)) {
148 if (sign.Sign (assemblyName))
149 Console.WriteLine ("Assembly signed");
151 Console.WriteLine ("Couldn't sign the assembly");
154 Console.WriteLine ("There is no public key present in assembly {0}", assemblyName);
157 static void Verify (string assemblyName, StrongName sn)
159 // this doesn't load the assembly (well it unloads it ;)
160 // http://weblogs.asp.net/nunitaddin/posts/9991.aspx
161 AssemblyName an = AssemblyName.GetAssemblyName (assemblyName);
163 Console.WriteLine ("Unable to load assembly: {0}", assemblyName);
167 if (an.Flags != AssemblyNameFlags.PublicKey) {
168 Console.WriteLine ("There is no public key present in assembly {0}", assemblyName);
172 if (sn.Verify (assemblyName))
173 Console.WriteLine ("Assembly {0} is strongnamed.", assemblyName);
175 Console.WriteLine ("Assembly {0} isn't strongnamed", assemblyName);
178 static bool Compare (byte[] value1, byte[] value2)
180 if ((value1 == null) || (value2 == null))
182 bool result = (value1.Length == value2.Length);
184 for (int i=0; i < value1.Length; i++) {
185 if (value1 [i] != value2 [i])
192 static void Help (string details)
194 Console.WriteLine ("Usage: sn [-q | -quiet] options [parameters]{0}", Environment.NewLine);
195 Console.WriteLine (" -q | -quiet \tQuiet mode (minimal display){0}", Environment.NewLine);
198 Console.WriteLine ("Configuration options <1>");
199 Console.WriteLine (" -c provider{0}\tChange the default CSP provider", Environment.NewLine);
200 Console.WriteLine (" -m [y|n]{0}\tUse a machine [y] key container or user key container [n]", Environment.NewLine);
201 Console.WriteLine (" -Vl{0}\tList the verification options", Environment.NewLine);
202 Console.WriteLine (" -Vr assembly [userlist]{0}\tExempt the specified assembly from verification for the user list", Environment.NewLine);
203 Console.WriteLine (" -Vu assembly{0}\tRemove exemption entry for the specified assembly", Environment.NewLine);
204 Console.WriteLine (" -Vx{0}\tRemove all exemptions entries", Environment.NewLine);
207 Console.WriteLine ("CSP related options <2>");
208 Console.WriteLine (" -d container{0}\tDelete the specified key container", Environment.NewLine);
209 Console.WriteLine (" -i keypair.snk container{0}\tImport the keypair from a SNK file into a CSP container", Environment.NewLine);
210 Console.WriteLine (" -pc container public.key{0}\tExport the public key from a CSP container to the specified file", Environment.NewLine);
213 Console.WriteLine ("Convertion options");
214 Console.WriteLine (" -e assembly output.pub{0}\tExport the assembly public key to the specified file", Environment.NewLine);
215 Console.WriteLine (" -p keypair.snk output.pub{0}\tExport the public key from a SNK file to the specified file", Environment.NewLine);
216 Console.WriteLine (" -o input output.txt{0}\tConvert the input file to a CSV file (using decimal).", Environment.NewLine);
217 Console.WriteLine (" -oh input output.txt{0}\tConvert the input file to a CSV file (using hexadecimal).", Environment.NewLine);
220 Console.WriteLine ("StrongName signing options");
221 Console.WriteLine (" -D assembly1 assembly2{0}\tCompare assembly1 and assembly2 (without signatures)", Environment.NewLine);
222 Console.WriteLine (" -k keypair.snk{0}\tCreate a new keypair in the specified file", Environment.NewLine);
223 Console.WriteLine (" -R assembly keypair.snk{0}\tResign the assembly with the specified StrongName key file", Environment.NewLine);
224 Console.WriteLine (" -Rc assembly container{0}\tResign the assembly with the specified CSP container", Environment.NewLine);
225 Console.WriteLine (" -t file{0}\tShow the public key from the specified file <1>", Environment.NewLine);
226 Console.WriteLine (" -tp file{0}\tShow the public key and pk token from the specified file <1>", Environment.NewLine);
227 Console.WriteLine (" -T assembly{0}\tShow the public key from the specified assembly", Environment.NewLine);
228 Console.WriteLine (" -Tp assembly{0}\tShow the public key and pk token from the specified assembly", Environment.NewLine);
229 Console.WriteLine (" -V assembly{0}\tVerify the specified assembly signature", Environment.NewLine);
230 Console.WriteLine (" -Vf assembly{0}\tVerify the specified assembly signature (even if disabled).", Environment.NewLine);
233 Console.WriteLine ("Help options");
234 Console.WriteLine (" -? | -h \tShow this help screen about the tool");
235 Console.WriteLine (" -? | -h config \tConfiguration options (see strongname.xml)");
236 Console.WriteLine (" -? | -h csp \tCrypto Service Provider (CSP) related options");
237 Console.WriteLine (" -? | -h convert\tFormat convertion options");
238 Console.WriteLine (" -? | -h sn \tStrongName signing options");
241 Console.WriteLine ("{0}<1> Currently not implemented in the tool", Environment.NewLine);
242 Console.WriteLine ("<2> Implemented in the tool but not in Mono{0}", Environment.NewLine);
246 static int Main (string[] args)
248 if (args.Length < 1) {
255 string param = args [i];
256 bool quiet = ((param == "-quiet") || (param == "-q"));
262 bool config = LoadConfig ();
264 StrongName sn = null;
265 AssemblyName an = null;
266 RSACryptoServiceProvider rsa = null;
267 CspParameters csp = new CspParameters ();
268 csp.ProviderName = defaultCSP;
270 switch (args [i++]) {
272 // Change global CSP provider options
273 defaultCSP = args [i];
274 return SaveConfig ();
276 // Delete specified key container
277 csp.KeyContainerName = args [i];
278 rsa = new RSACryptoServiceProvider (csp);
279 rsa.PersistKeyInCsp = false;
281 Console.WriteLine ("Keypair in container {0} has been deleted", args [i]);
284 StrongName a1 = new StrongName ();
285 byte[] h1 = a1.Hash (args [i++]);
286 StrongName a2 = new StrongName ();
287 byte[] h2 = a2.Hash (args [i++]);
288 if (Compare (h1, h2)) {
289 Console.WriteLine ("Both assembly are identical (same digest for metadata)");
290 // TODO: if equals then compare signatures
293 Console.WriteLine ("Assemblies are not identical (different digest for metadata)");
296 // Export public key from assembly
297 an = AssemblyName.GetAssemblyName (args [i++]);
298 WriteToFile (args[i], an.GetPublicKey ());
300 Console.WriteLine ("Public Key extracted to file {0}", args [i]);
303 // import keypair from SNK to container
304 sn = new StrongName (ReadFromFile (args [i++]));
305 csp.KeyContainerName = args [i];
306 rsa = new RSACryptoServiceProvider (csp);
307 rsa.ImportParameters (sn.RSA.ExportParameters (true));
310 // Create a new strong name key pair
311 // (a new RSA keypair automagically if none is present)
312 sn = new StrongName ();
313 WriteToFile (args[i], CryptoConvert.ToCapiKeyBlob (sn.RSA, true));
315 Console.WriteLine ("A new strong name keypair has been generated in {0}", args [i]);
318 byte[] infileD = ReadFromFile (args [i++]);
319 WriteCSVToFile (args [i], infileD, "D");
321 Console.WriteLine ("Output CVS file is {0} (decimal format)", args [i]);
324 byte[] infileX2 = ReadFromFile (args [i++]);
325 WriteCSVToFile (args [i], infileX2, "X2");
327 Console.WriteLine ("Output CVS file is {0} (hexadecimal format)", args [i]);
330 // Extract public key from SNK file
331 sn = new StrongName (ReadFromFile (args [i++]));
332 WriteToFile (args[i], sn.PublicKey);
334 Console.WriteLine ("Public Key extracted to file {0}", args [i]);
337 // Extract public key from container
338 csp.KeyContainerName = args [i++];
339 rsa = new RSACryptoServiceProvider (csp);
340 sn = new StrongName (rsa);
341 WriteToFile (args[i], sn.PublicKey);
343 Console.WriteLine ("Public Key extracted to file {0}", args [i]);
346 string filename = args [i++];
347 sn = new StrongName (ReadFromFile (args [i]));
348 ReSign (filename, sn.RSA);
351 filename = args [i++];
352 csp.KeyContainerName = args [i];
353 rsa = new RSACryptoServiceProvider (csp);
354 ReSign (filename, rsa);
357 // Show public key token from file
358 sn = new StrongName (ReadFromFile (args [i]));
359 // note: ignore quiet
360 Console.WriteLine ("Public Key Token: " + ToString (sn.PublicKeyToken), Environment.NewLine);
363 // Show public key and public key token from assembly
364 sn = new StrongName (ReadFromFile (args [i]));
365 // note: ignore quiet
366 Console.WriteLine ("Public Key:" + ToString (sn.PublicKey));
367 Console.WriteLine ("{0}Public Key Token: " + ToString (sn.PublicKeyToken), Environment.NewLine);
370 // Show public key token from assembly
371 an = AssemblyName.GetAssemblyName (args [i++]);
372 // note: ignore quiet
373 byte [] pkt = an.GetPublicKeyToken ();
375 Console.WriteLine ("{0} does not represent a strongly named assembly.", args [i - 1]);
377 Console.WriteLine ("Public Key Token: " + ToString (pkt));
381 // Show public key and public key token from assembly
382 an = AssemblyName.GetAssemblyName (args [i++]);
383 byte [] token = an.GetPublicKeyToken ();
385 Console.WriteLine ("{0} does not represent a strongly named assembly.", args [i - 1]);
387 Console.WriteLine ("Public Key:" + ToString (an.GetPublicKey ()));
388 Console.WriteLine ("{0}Public Key Token: " + ToString (token), Environment.NewLine);
392 filename = args [i++];
393 an = AssemblyName.GetAssemblyName (filename);
394 byte[] akey = an.GetPublicKey ();
395 if(akey == null || akey.Length < 12) {
396 Console.WriteLine (filename + " is not a strongly named assembly");
399 byte[] pkey = new byte [akey.Length - 12];
400 Buffer.BlockCopy (akey, 12, pkey, 0, pkey.Length);
401 sn = new StrongName (pkey);
402 Verify (filename, sn);
405 Console.WriteLine ("Unimplemented option");
408 Console.WriteLine ("Unimplemented option");
411 Console.WriteLine ("Unimplemented option");
414 Console.WriteLine ("Unimplemented option");
417 Console.WriteLine ("Unimplemented option");
421 Help ((i < args.Length) ? args [i] : null);
425 Console.WriteLine ("Unknown option {0}", args [i-1]);