Recover “lost” CRM encryption key

Have you ever had “Data encryption can’t be activated because the encryption key doesn’t match the source encryption key used to encrypt the data” error when trying to activate/change encryption key on organization that was imported or upgraded from previous CRM version?
If you’re on on-prem and you have MSCRM_CONFIG database of source organization, you can recover your key – that told if you don’t have backed it up 🙂

First, let’s retrieve it from database:

SELECT ColumnName, VarBinaryColumn FROM OrganizationProperties
WHERE Id IN (SELECT Id FROM Organization WHERE UniqueName = '<OrgUniqName>')
AND (ColumnName = 'SymmetricKeySource')

It will look like “0xABCDEF”, looks like hexstring, let’s decode:

var sb = new StringBuilder();
var str = "0x37323A303A3130313A303A3130383A303A3130383A303A3131313A303A33323A303A38343A303A3130343A303A3130353A303A3131353A303A33323A303A37333A303A3131353A303A33323A303A3131323A303A39373A303A3131353A303A3131353A303A36343A303A3131393A303A3131313A303A3131343A303A3130303A303A34393A303A33323A303A3130323A303A3131343A303A3131313A303A3130393A303A33323A303A36373A303A38323A303A37373A30";
for (int i = 2; i < str.Length; i += 2)
{
var b1 = byte.Parse(str.Substring(i, 2), NumberStyles.HexNumber);

var part = ASCIIEncoding.ASCII.GetString(new byte[] { b1 });

sb.Append(part);
}
Console.WriteLine(sb);

Now it should look like this:

72:0:101:0:108:0:108:0:111:0:32:0:84:0:104:0:105:0:115:0:32:0:73:0:115:0:32:0:112:0:97:0:115:0:115:0:64:0:119:0:111:0:114:0:100:0:49:0:32:0:102:0:114:0:111:0:109:0:32:0:67:0:82:0:77:0

As you know, password can be Unicode, so here we go again:

var parts = sb.ToString().Split(':');
sb.Clear();
for (int i = 0; i < parts.Length; i += 2)
{
var b1 = byte.Parse(parts[i]);
var b2 = byte.Parse(parts[i + 1]);
var part = UnicodeEncoding.Unicode.GetString(new byte[] { b1, b2 });
sb.Append(part);
}
Console.WriteLine(sb);

And we have our password: Hello This Is pass@word1 from CRM.

Compare this with CRM to be sure:
CRM Encryption Key

Hope this will help someone.

CRM Security Roles Summary

To quickly view which role have what rights, You can use this SQL query:

SELECT  DISTINCT
        r.Name
        ,COALESCE(e.OriginalLocalizedName, e.Name) AS EntityName
        ,CASE p.AccessRight
             WHEN 32     THEN 'Create' 
             WHEN 1      THEN 'Read'
             WHEN 2      THEN 'Write'
             WHEN 65536  THEN 'Delete' 
             WHEN 4      THEN 'Append'
             WHEN 16     THEN 'AppendTo'
             WHEN 524288 THEN 'Assign' 
             WHEN 262144 THEN 'Share' 
             ELSE 'None'
        END AS [Privilege]
        ,CASE (rp.PrivilegeDepthMask % 0x0F)
             WHEN 1 THEN 'User (Basic)'
             WHEN 2 THEN 'Business Unit (Local)'
             WHEN 4 THEN 'Parental (Deep)'
             WHEN 8 THEN 'Organization (Global)'
             ELSE 'Unknown'
        END AS [PrivilegeLevel]
        ,(rp.PrivilegeDepthMask % 0x0F) as PrivilegeDepthMask
        ,CASE WHEN e.IsCustomEntity = 1 THEN 'Yes' ELSE 'No' END AS IsCustomEntity
FROM    Role AS r
INNER JOIN RolePrivileges AS rp ON r.RoleId = rp.RoleId
INNER JOIN Privilege AS p ON rp.PrivilegeId = p.PrivilegeId
INNER JOIN PrivilegeObjectTypeCodes AS potc ON potc.PrivilegeId = p.PrivilegeId
INNER JOIN MetadataSchema.Entity AS e ON e.ObjectTypeCode = potc.ObjectTypeCode
ORDER BY r.Name, EntityName

Get strongly typed attribute logical name for CRM Entity

When using early bound entities, there’s a easy way to get CRM entity logical attribute name thanks to AttributeLogicalNameAttribute attribute in generated code. You can use this simple extension method:

        public static string GetEntityPropertyLogicalName<E, P>(this E src, Expression<Func<E, P>> expression)
        {
            var member = expression.Body as MemberExpression;
            if (member != null && member.Member is PropertyInfo)
            {
                var pi = member.Member as PropertyInfo;
                var pn = pi.Name;

                var epi = typeof(E).GetProperty(pn);
                var attr = (AttributeLogicalNameAttribute) epi.GetCustomAttribute(typeof(AttributeLogicalNameAttribute));

                if (attr == null)
                {
                    throw new System.ArgumentNullException(pn, "AttributeLogicalNameAttribute not found on property");
                }

                return attr.LogicalName;
            }

            throw new ArgumentException("Expression is not a Property");
        }

And usage is very simple:

            var account = new Account();
            var line1 = account.GetEntityPropertyLogicalName(p => p.Address1_Line1);

Now line1 should contain address1_line1 string.