Skip to content

Commit 2451eed

Browse files
committed
Simplify crypto logic.
1 parent 2af19e6 commit 2451eed

File tree

3 files changed

+33
-13
lines changed

3 files changed

+33
-13
lines changed

src/datastore/DataStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ export interface DataStore extends ProvisioningStore {
175175

176176
removePass(userId: string, domain: string): Promise<void>;
177177

178+
removeClientCert(userId: string, domain: string): Promise<void>;
179+
178180
getMatrixUserByUsername(domain: string, username: string): Promise<MatrixUser|undefined>;
179181

180182
getCountForUsernamePrefix(domain: string, usernamePrefix: string): Promise<number>;

src/datastore/StringCrypto.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,41 @@ export class StringCrypto {
4848
}
4949

5050
public encrypt(plaintext: string): string {
51+
if (plaintext.includes(' ')) {
52+
throw Error('Cannot encode spaces')
53+
}
5154
const salt = crypto.randomBytes(16).toString('base64');
5255
return crypto.publicEncrypt(
5356
this.privateKey,
5457
Buffer.from(salt + ' ' + plaintext)
5558
).toString('base64');
5659
}
5760

61+
public encryptLargeString(plaintext: string): string {
62+
const cryptoParts = [];
63+
while (plaintext.length > 0) {
64+
const part = plaintext.slice(0, 64);
65+
cryptoParts.push(this.encrypt(part));
66+
plaintext = plaintext.slice(64);
67+
}
68+
return 'lg:' + cryptoParts.join(',');
69+
}
70+
71+
5872
public decrypt(encryptedString: string): string {
5973
const decryptedPass = crypto.privateDecrypt(
6074
this.privateKey,
6175
Buffer.from(encryptedString, 'base64')
6276
).toString();
6377
// Extract the password by removing the prefixed salt and seperating space
64-
return decryptedPass.split(' ')[1];
78+
return decryptedPass.slice(17)[1];
79+
}
80+
81+
public decryptLargeString(encryptedString: string): string {
82+
if (encryptedString !== 'lg:') {
83+
throw Error('Not a large string');
84+
}
85+
encryptedString = encryptedString.slice(3);
86+
return encryptedString.split(',').map(v => this.decrypt(v)).join('');
6587
}
6688
}

src/datastore/postgres/PgDataStore.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,7 @@ export class PgDataStore implements DataStore, ProvisioningStore {
536536
const cryptoStore = this.cryptoStore;
537537
if (config.certificate && row.key && cryptoStore) {
538538
try {
539-
const keyParts = row.key.split(',').map(v => cryptoStore.decrypt(v));
540-
config.certificate.key = `-----BEGIN PRIVATE KEY-----\n${keyParts.join('')}-----END PRIVATE KEY-----\n`;
539+
config.certificate.key = cryptoStore.decryptLargeString(row.key);
541540
}
542541
catch (ex) {
543542
log.warn(`Failed to decrypt TLS key for ${userId} ${domain}`, ex);
@@ -565,16 +564,7 @@ export class PgDataStore implements DataStore, ProvisioningStore {
565564

566565
if (config.certificate && this.cryptoStore) {
567566
keypair.cert = config.certificate.cert;
568-
const cryptoParts = [];
569-
let key = config.certificate.key;
570-
// We can't store these as our encryption system doesn't support spaces.
571-
key = key.replace('-----BEGIN PRIVATE KEY-----\n', '').replace('-----END PRIVATE KEY-----\n', '');
572-
while (key.length > 0) {
573-
const part = key.slice(0, 64);
574-
cryptoParts.push(this.cryptoStore.encrypt(part));
575-
key = key.slice(64);
576-
}
577-
keypair.key = cryptoParts.join(',');
567+
keypair.key = this.cryptoStore.encryptLargeString(config.certificate.key);
578568
}
579569
const parameters = {
580570
user_id: userId,
@@ -679,6 +669,12 @@ export class PgDataStore implements DataStore, ProvisioningStore {
679669
[userId, domain]);
680670
}
681671

672+
public async removeClientCert(userId: string, domain: string): Promise<void> {
673+
await this.pgPool.query(
674+
"UPDATE client_config SET cert = NULL AND key = NULL WHERE user_id = $1 AND domain = $2",
675+
[userId, domain]);
676+
}
677+
682678
public async getMatrixUserByUsername(domain: string, username: string): Promise<MatrixUser|undefined> {
683679
// This will need a join
684680
const res = await this.pgPool.query(

0 commit comments

Comments
 (0)