/// <summary> /// Main entrypoint for the download program. /// </summary> /// <param name="args"> parameters passed in from the user </param> private static async Task Main(string[] args) { DetectCryptographyTool detectCryptographyTool = new DetectCryptographyTool(); Logger.Info($"Microsoft OSS Gadget - {TOOL_NAME} {VERSION}"); detectCryptographyTool.ParseOptions(args); // select output destination and format detectCryptographyTool.SelectOutput((string?)detectCryptographyTool.Options["output-file"] ?? ""); IOutputBuilder outputBuilder = detectCryptographyTool.SelectFormat((string?)detectCryptographyTool.Options["format"] ?? "text"); if (detectCryptographyTool.Options["target"] is IList <string> targetList && targetList.Count > 0) { var sb = new StringBuilder(); foreach (var target in targetList) { sb.Clear(); try { List <IssueRecord>?results = null; if (target.StartsWith("pkg:", StringComparison.InvariantCulture)) { var purl = new PackageURL(target); results = await(detectCryptographyTool.AnalyzePackage(purl, (string?)detectCryptographyTool.Options["download-directory"] ?? string.Empty, (bool?)detectCryptographyTool.Options["use-cache"] == true) ?? Task.FromResult(new List <IssueRecord>())); } else if (Directory.Exists(target)) { results = await(detectCryptographyTool.AnalyzeDirectory(target) ?? Task.FromResult(new List <IssueRecord>())); } else if (File.Exists(target)) { string?targetDirectoryName = null; while (targetDirectoryName == null || Directory.Exists(targetDirectoryName)) { targetDirectoryName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); } var projectManager = ProjectManagerFactory.CreateBaseProjectManager(targetDirectoryName); #pragma warning disable SCS0018 // Path traversal: injection possible in {1} argument passed to '{0}' var path = await projectManager.ExtractArchive("temp", File.ReadAllBytes(target)); #pragma warning restore SCS0018 // Path traversal: injection possible in {1} argument passed to '{0}' results = await(detectCryptographyTool.AnalyzeDirectory(path) ?? Task.FromResult(new List <IssueRecord>()));; // Clean up after ourselves try { if (targetDirectoryName != null) { Directory.Delete(targetDirectoryName, true); } } catch (Exception ex) { Logger.Warn("Unable to delete {0}: {1}", targetDirectoryName, ex.Message); } } if (results == null) { Logger.Warn("Error generating results, was null."); } else if (!results.Any()) { sb.AppendLine($"[ ] {target} - This software package does NOT appear to implement cryptography."); } else { var shortTags = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>()) .Distinct() .Where(t => t.StartsWith("Cryptography.Implementation.")) .Select(t => t.Replace("Cryptography.Implementation.", "")); var otherTags = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>()) .Distinct() .Where(t => !t.StartsWith("Cryptography.Implementation.")); if (shortTags.Any()) { sb.AppendLine($"[X] {target} - This software package appears to implement {string.Join(", ", shortTags)}."); } if (otherTags.Contains("Cryptography.GenericImplementation.HighDensityOperators")) { sb.AppendLine($"[X] {target} - This software package has a high-density of cryptographic operators."); } else { sb.AppendLine($"[ ] {target} - This software package does NOT have a high-density of cryptographic operators."); } if (otherTags.Contains("Cryptography.GenericImplementation.CryptographicWords")) { sb.AppendLine($"[X] {target} - This software package contains words that suggest cryptography."); } else { sb.AppendLine($"[ ] {target} - This software package does NOT contains words that suggest cryptography."); } if ((bool?)detectCryptographyTool.Options["verbose"] == true) { var items = results.GroupBy(k => k.Issue.Rule.Name).OrderByDescending(k => k.Count()); foreach (var item in items) { sb.AppendLine(); sb.AppendLine($"There were {item.Count()} finding(s) of type [{item.Key}]."); foreach (var result in results) { if (result.Issue.Rule.Name == item.Key) { sb.AppendLine($" {result.Filename}:"); if (result.Issue.Rule.Id == "_CRYPTO_DENSITY") { // No excerpt for cryptogrpahic density // TODO: We stuffed the density in the unused 'Description' field. This is code smell. sb.AppendLine($" | The maximum cryptographic density is {result.Issue.Rule.Description}."); } else { // Show the excerpt foreach (var line in result.TextSample.Split(new char[] { '\n', '\r' })) { if (!string.IsNullOrWhiteSpace(line)) { sb.AppendLine($" | {line.Trim()}"); } } } sb.AppendLine(); } } } } if (Logger.IsDebugEnabled) { foreach (var result in results) { Logger.Debug($"Result: {result.Filename} {result.Issue.Rule.Name} {result.TextSample}"); } } } Console.WriteLine(sb.ToString()); } catch (Exception ex) { Logger.Warn(ex, "Error processing {0}: {1}", target, ex.Message); Logger.Warn(ex.StackTrace); } } } else { Logger.Warn("No target provided; nothing to analyze."); DetectCryptographyTool.ShowUsage(); Environment.Exit(1); } }
/// <summary> /// Main entrypoint for the download program. /// </summary> /// <param name="args">parameters passed in from the user</param> private static async Task Main(string[] args) { ShowToolBanner(); DetectCryptographyTool detectCryptographyTool = new DetectCryptographyTool(); detectCryptographyTool.ParseOptions(args); // select output destination and format detectCryptographyTool.SelectOutput((string?)detectCryptographyTool.Options["output-file"] ?? ""); IOutputBuilder outputBuilder = detectCryptographyTool.SelectFormat((string?)detectCryptographyTool.Options["format"] ?? "text"); if (detectCryptographyTool.Options["target"] is IList <string> targetList && targetList.Count > 0) { StringBuilder?sb = new StringBuilder(); foreach (string?target in targetList) { sb.Clear(); try { List <IssueRecord>?results = null; if (target.StartsWith("pkg:", StringComparison.InvariantCulture)) { PackageURL?purl = new PackageURL(target); results = await(detectCryptographyTool.AnalyzePackage(purl, (string?)detectCryptographyTool.Options["download-directory"] ?? string.Empty, (bool?)detectCryptographyTool.Options["use-cache"] == true) ?? Task.FromResult(new List <IssueRecord>())); } else if (System.IO.Directory.Exists(target)) { results = await(detectCryptographyTool.AnalyzeDirectory(target) ?? Task.FromResult(new List <IssueRecord>())); } else if (File.Exists(target)) { string?targetDirectoryName = null; while (targetDirectoryName == null || System.IO.Directory.Exists(targetDirectoryName)) { targetDirectoryName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); } string?path = await ArchiveHelper.ExtractArchiveAsync(targetDirectoryName, Path.GetFileName(target), File.OpenRead(target)); results = await detectCryptographyTool.AnalyzeDirectory(path); // Clean up after ourselves } else { Logger.Warn($"{target} was neither a Package URL, directory, nor a file."); continue; } if (results == null) { Logger.Warn("No results were generated."); continue; } else { sb.AppendLine("Summary Results:"); sb.AppendLine(Blue("Cryptographic Implementations:")); IOrderedEnumerable <string>?implementations = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>()) .Distinct() .Where(t => t.StartsWith("Cryptography.Implementation.")) .Select(t => t.Replace("Cryptography.Implementation.", "")) .OrderBy(s => s); if (implementations.Any()) { foreach (string?tag in implementations) { sb.AppendLine(Bright.Blue($" * {tag}")); } } else { sb.AppendLine(Bright.Black(" No implementations found.")); } sb.AppendLine(); sb.AppendLine(Red("Cryptographic Library References:")); IOrderedEnumerable <string>?references = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>()) .Distinct() .Where(t => t.StartsWith("Cryptography.Reference.")) .Select(t => t.Replace("Cryptography.Reference.", "")) .OrderBy(s => s); if (references.Any()) { foreach (string?tag in references) { sb.AppendLine(Bright.Red($" * {tag}")); } } else { sb.AppendLine(Bright.Black(" No library references found.")); } sb.AppendLine(); sb.AppendLine(Green("Other Cryptographic Characteristics:")); IOrderedEnumerable <string>?characteristics = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>()) .Distinct() .Where(t => t.Contains("Crypto", StringComparison.InvariantCultureIgnoreCase) && !t.StartsWith("Cryptography.Implementation.") && !t.StartsWith("Cryptography.Reference.")) .Select(t => t.Replace("Cryptography.", "")) .OrderBy(s => s); if (characteristics.Any()) { foreach (string?tag in characteristics) { sb.AppendLine(Bright.Green($" * {tag}")); } } else { sb.AppendLine(Bright.Black(" No additional characteristics found.")); } if ((bool?)detectCryptographyTool.Options["verbose"] == true) { IOrderedEnumerable <IGrouping <string, IssueRecord> >?items = results.GroupBy(k => k.Issue.Rule.Name).OrderByDescending(k => k.Count()); foreach (IGrouping <string, IssueRecord>?item in items) { sb.AppendLine(); sb.AppendLine($"There were {item.Count()} finding(s) of type [{item.Key}]."); foreach (IssueRecord?result in results) { if (result.Issue.Rule.Name == item.Key) { sb.AppendLine($" {result.Filename}:"); if (result.Issue.Rule.Id == "_CRYPTO_DENSITY") { // No excerpt for cryptographic density // TODO: We stuffed the density in the unused 'Description' field. This is code smell. sb.AppendLine($" | The maximum cryptographic density is {result.Issue.Rule.Description}."); } else { // Show the excerpt foreach (string?line in result.TextSample.Split(new char[] { '\n', '\r' })) { if (!string.IsNullOrWhiteSpace(line)) { sb.AppendLine($" | {line.Trim()}"); } } } sb.AppendLine(); } } } } if (Logger.IsDebugEnabled) { foreach (IssueRecord?result in results) { Logger.Debug($"Result: {result.Filename} {result.Issue.Rule.Name} {result.TextSample}"); } } } Console.WriteLine(sb.ToString()); } catch (Exception ex) { Logger.Warn(ex, "Error processing {0}: {1}", target, ex.Message); Logger.Warn(ex.StackTrace); } } } else { Logger.Warn("No target provided; nothing to analyze."); DetectCryptographyTool.ShowUsage(); Environment.Exit(1); } }