0

I'm coding a little helper utility for encrypting and decrypting strings using the dotnet core windows data protection api (dpapi).

Here is the full Program.cs (both nuget packages are version 3.1.3):

using System;
using System.Linq;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;

namespace deleteme
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("Nothing to do");
                return;
            }

            var coll = new ServiceCollection();
            coll.AddDataProtection();
            var svc = coll.BuildServiceProvider();
            var dpapi = ActivatorUtilities.CreateInstance<Protector>(svc);

            var op = args.FirstOrDefault();

            if (op == "encsave")
            {
                if (args.Length != 3)
                {
                    Console.WriteLine("Need exactly 3 args, \"encsave\", the plaintext secret and the path");
                    return;
                }
                var data = args[1];
                var path = args[2];
                System.IO.File.AppendAllText(path, dpapi.Encrypt(data), System.Text.Encoding.UTF8);
                Console.WriteLine(path);
                Console.WriteLine(dpapi.Encrypt(data));
            }
            else if (op == "enc")
            {
                if (args.Length != 2)
                {
                    Console.WriteLine("Need exactly 2 args, \"enc\" and the plaintext secret");
                    return;
                }
                var data = args[1];
                Console.WriteLine(dpapi.Encrypt(data));
            }
            else if (op == "dec")
            {
                if (args.Length != 2)
                {
                    Console.WriteLine("Need exactly 2 args, \"dec\" and the path");
                    return;
                }
                var path = args[1];
                var content = System.IO.File.ReadAllText(path);
                Console.WriteLine(dpapi.Decrypt(content));
            }
            else
            {
                Console.WriteLine("Invalid op");
                return;
            }
        }
    }

    public class Protector
    {
        IDataProtector _protector;
        public Protector(IDataProtectionProvider objProvider) => _protector = objProvider.CreateProtector("meh");
        public string Encrypt(string plainText) => _protector.Protect(plainText);
        public string Decrypt(string encrypted) => _protector.Unprotect(encrypted);
    }
}

When I'm running it with dotnet run enc encryptme here's the error message I'm getting. Does someone spot an obvious mistake? Any help is appreciated! Thanks

Unhandled exception. System.Security.Cryptography.CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information.
 ---> System.EntryPointNotFoundException: Unable to find an entry point named 'CryptProtectMemory' in DLL 'crypt32.dll'.
   at Microsoft.AspNetCore.Cryptography.UnsafeNativeMethods.CryptProtectMemory(SafeHandle pData, UInt32 cbData, UInt32 dwFlags)
   at Microsoft.AspNetCore.DataProtection.MemoryProtection.CryptProtectMemory(SafeHandle pBuffer, UInt32 byteCount)
   at Microsoft.AspNetCore.DataProtection.Secret.Protect(Byte* pbPlaintext, UInt32 cbPlaintext)
   at Microsoft.AspNetCore.DataProtection.Secret..ctor(Byte* secret, Int32 secretLength)
   at Microsoft.AspNetCore.DataProtection.Secret.Random(Int32 numBytes)
   at Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorConfiguration.CreateNewDescriptor()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.CreateNewKey(Guid keyId, DateTimeOffset creationDate, DateTimeOffset activationDate, DateTimeOffset expirationDate)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.CreateNewKey(DateTimeOffset activationDate, DateTimeOffset expirationDate)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.ICacheableKeyRingProvider.GetCacheableKeyRing(DateTimeOffset now)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRingCore(DateTime utcNow, Boolean forceRefresh)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRing()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext)
   at Microsoft.AspNetCore.DataProtection.DataProtectionCommonExtensions.Protect(IDataProtector protector, String plaintext)
   at deleteme.Protector.Encrypt(String plainText) in C:\Users\username\source\dpapi\Program.cs:line 71
   at deleteme.Program.Main(String[] args) in C:\Users\username\source\dpapi\Program.cs:line 46
baouss
  • 1,312
  • 1
  • 22
  • 52
  • And you are running it on Windows? – Klaus Gütter Apr 25 '20 at 13:28
  • Yes, Windows 10 Pro. – baouss Apr 25 '20 at 17:31
  • 1
    Hmm, I can reproduce this with your code. No idea what happens here, sorry. – Klaus Gütter Apr 26 '20 at 07:07
  • I have two systems, one where it works, one where it fails with the same error. I checked the versions of crypt32.dll on them, and found two separate versions: 6.2.17134.1246 where it works and 6.2.17763.973 where it fails. Apparently the DLL was updated on one of my systems and not on another and the newer version no longer supports that entry point? – BardMorgan Sep 09 '20 at 20:32

0 Answers0