Skip to content

Commit 4f29250

Browse files
committed
Just try all the keys
Trying to find the right key by name is error prone and often leads to issues. It's more effective to try all keys of the given etype since it's still bound by the total length of keys in the table.
1 parent 97ddeb9 commit 4f29250

2 files changed

Lines changed: 68 additions & 26 deletions

File tree

Kerberos.NET/Crypto/DecryptedKrbApReq.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
// -----------------------------------------------------------------------
55

66
using System;
7+
using System.Linq;
8+
using System.Security;
9+
using System.Security.Cryptography;
710
using Kerberos.NET.Entities;
811

912
namespace Kerberos.NET.Crypto
@@ -65,9 +68,38 @@ public override void Decrypt(KeyTable keytab)
6568
throw new ArgumentNullException(nameof(keytab));
6669
}
6770

68-
var key = keytab.GetKey(this.EType, this.SName);
71+
var keys = keytab.GetKeys(this.EType, this.SName);
6972

70-
this.Decrypt(key);
73+
if (!keys.Any())
74+
{
75+
throw new InvalidOperationException($"Could not find a key for {this.EType} and {this.SName.FullyQualifiedName}");
76+
}
77+
78+
Exception ex = null;
79+
80+
foreach (var key in keys)
81+
{
82+
try
83+
{
84+
this.Decrypt(key);
85+
return;
86+
}
87+
catch (CryptographicException cex)
88+
{
89+
ex = cex;
90+
continue;
91+
}
92+
catch (SecurityException secx)
93+
{
94+
ex = secx;
95+
continue;
96+
}
97+
}
98+
99+
if (ex != null)
100+
{
101+
throw ex;
102+
}
71103
}
72104

73105
public override void Decrypt(KerberosKey ticketEncryptingKey)

Kerberos.NET/Crypto/KeyTable.cs

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,28 +74,44 @@ public void Write(BinaryWriter writer)
7474

7575
private ICollection<KeyEntry> entries;
7676

77-
public ICollection<KeyEntry> Entries => this.entries ?? (this.entries = new List<KeyEntry>());
77+
public ICollection<KeyEntry> Entries => this.entries ??= new List<KeyEntry>();
7878

7979
public KerberosKey GetKey(ChecksumType type, KrbPrincipalName sname)
8080
{
81-
EncryptionType etype;
81+
var etype = type switch
82+
{
83+
ChecksumType.HMAC_SHA1_96_AES128 => EncryptionType.AES128_CTS_HMAC_SHA1_96,
84+
ChecksumType.HMAC_SHA1_96_AES256 => EncryptionType.AES256_CTS_HMAC_SHA1_96,
85+
_ => EncryptionType.RC4_HMAC_NT,
86+
};
87+
return this.GetKey(etype, sname);
88+
}
89+
90+
public IEnumerable<KerberosKey> GetKeys(EncryptionType type, KrbPrincipalName sname)
91+
{
92+
// try and find a matching entry
93+
94+
var entries = this.Entries
95+
.Where(e => e.EncryptionType == type && (sname?.Matches(e.Principal) ?? true))
96+
.OrderByDescending(x => x.Version);
97+
98+
if (!entries.Any())
99+
{
100+
// Fall back to first entry with matching type
82101

83-
switch (type)
102+
entries = this.Entries
103+
.Where(e => e.EncryptionType == type)
104+
.OrderByDescending(x => x.Version);
105+
}
106+
107+
if (!entries.Any())
84108
{
85-
case ChecksumType.HMAC_SHA1_96_AES128:
86-
etype = EncryptionType.AES128_CTS_HMAC_SHA1_96;
87-
break;
88-
case ChecksumType.HMAC_SHA1_96_AES256:
89-
etype = EncryptionType.AES256_CTS_HMAC_SHA1_96;
90-
break;
91-
92-
case ChecksumType.KERB_CHECKSUM_HMAC_MD5:
93-
default:
94-
etype = EncryptionType.RC4_HMAC_NT;
95-
break;
109+
// fall back to first entry
110+
111+
entries = this.Entries.OrderByDescending(x => x.Version);
96112
}
97113

98-
return this.GetKey(etype, sname);
114+
return entries.Select(e => e.Key);
99115
}
100116

101117
public KerberosKey GetKey(EncryptionType type, KrbPrincipalName sname)
@@ -107,22 +123,16 @@ public KerberosKey GetKey(EncryptionType type, KrbPrincipalName sname)
107123
.OrderByDescending(x => x.Version)
108124
.FirstOrDefault();
109125

110-
// Fall back to first entry with matching type (RC4_HMAC_NT)
126+
// Fall back to first entry with matching type
111127

112-
if (entry == null)
113-
{
114-
entry = this.Entries
128+
entry ??= this.Entries
115129
.Where(e => e.EncryptionType == type)
116130
.OrderByDescending(x => x.Version)
117131
.FirstOrDefault();
118-
}
119132

120133
// Fall back to first entry
121134

122-
if (entry == null)
123-
{
124-
entry = this.Entries.FirstOrDefault();
125-
}
135+
entry ??= this.Entries.FirstOrDefault();
126136

127137
return entry?.Key;
128138
}

0 commit comments

Comments
 (0)