commit fbb6ad0646e7bd20bc8a752aa8ccc2c998109a36
parent 469c713786018aa344604aebc283a1e943cb4ffb
Author: Wim Dupont <wim@wimdupont.com>
Date: Sat, 23 Dec 2023 14:00:25 +0100
refactor and added tests
Diffstat:
10 files changed, 331 insertions(+), 145 deletions(-)
diff --git a/pom.xml b/pom.xml
@@ -7,31 +7,48 @@
<groupId>com.wimdupont</groupId>
<artifactId>TotpGenerator</artifactId>
<version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <maven.compiler.source>21</maven.compiler.source>
+ <maven.compiler.target>21</maven.compiler.target>
+ <commons-codec.version>1.16.0</commons-codec.version>
+ <bcpg-jdk18on.version>1.77</bcpg-jdk18on.version>
+ <otp-java.version>2.0.3</otp-java.version>
+ <junit-jupiter-engine.version>5.10.1</junit-jupiter-engine.version>
+ <mockito-inline.version>5.2.0</mockito-inline.version>
+ <maven-surefire-plugin.version>3.2.3</maven-surefire-plugin.version>
+ </properties>
+
<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
- <version>1.16.0</version>
+ <version>${commons-codec.version}</version>
</dependency>
-
- <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpg-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk18on</artifactId>
- <version>1.77</version>
+ <version>${bcpg-jdk18on.version}</version>
</dependency>
<dependency>
<groupId>com.github.bastiaanjansen</groupId>
<artifactId>otp-java</artifactId>
- <version>2.0.3</version>
+ <version>${otp-java.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <version>${junit-jupiter-engine.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-inline</artifactId>
+ <version>${mockito-inline.version}</version>
+ <scope>test</scope>
</dependency>
</dependencies>
- <properties>
- <maven.compiler.source>21</maven.compiler.source>
- <maven.compiler.target>21</maven.compiler.target>
- </properties>
-
<build>
<plugins>
<plugin>
@@ -68,6 +85,15 @@
</archive>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${maven-surefire-plugin.version}</version>
+ <configuration>
+<!-- Should remove when no longer required-->
+ <argLine>-Dnet.bytebuddy.experimental=true</argLine>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/src/main/java/com/wimdupont/Main.java b/src/main/java/com/wimdupont/Main.java
@@ -1,20 +1,28 @@
package com.wimdupont;
import com.bastiaanjansen.otp.TOTPGenerator;
-import com.wimdupont.service.GpgUtil;
+import com.wimdupont.service.GpgService;
import com.wimdupont.service.PropertiesLoader;
-import org.bouncycastle.openpgp.PGPException;
-
-import java.io.IOException;
public class Main {
- public static void main(String[] args) throws PGPException, IOException {
- String fileArgument = args.length > 0
+ public static void main(String[] args) {
+ try {
+ var gpgService = new GpgService(new PropertiesLoader().loadProperties());
+ System.out.println(TOTPGenerator
+ .withDefaultValues(gpgService
+ .decrypt(getFileArg(args)))
+ .now());
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ System.exit(0);
+ }
+ }
+
+ private static String getFileArg(String... args) {
+ return args.length > 0
? args[0]
: null;
- GpgUtil gpgUtil = new GpgUtil(new PropertiesLoader().loadProperties());
- System.out.println(TOTPGenerator.withDefaultValues(gpgUtil.decrypt(fileArgument)).now());
- System.exit(0);
}
}
diff --git a/src/main/java/com/wimdupont/service/GpgService.java b/src/main/java/com/wimdupont/service/GpgService.java
@@ -0,0 +1,122 @@
+package com.wimdupont.service;
+
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPCompressedData;
+import org.bouncycastle.openpgp.PGPEncryptedData;
+import org.bouncycastle.openpgp.PGPEncryptedDataList;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPLiteralData;
+import org.bouncycastle.openpgp.PGPObjectFactory;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
+import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
+import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidParameterException;
+import java.security.Security;
+import java.util.Iterator;
+import java.util.Properties;
+
+public class GpgService {
+
+ private final String dirPath;
+ private final String secretFile;
+
+ public GpgService(Properties properties) {
+ dirPath = properties.getProperty("dir.path");
+ secretFile = properties.getProperty("secret.file");
+
+ if (dirPath == null | secretFile == null) {
+ throw new InvalidParameterException("Properties missing.");
+ }
+ }
+
+ public byte[] decrypt(String fileName) throws IOException, PGPException {
+ Security.addProvider(new BouncyCastleProvider());
+
+ var encryptedDataObjects = getPgpEncryptedDataIterator(fileName);
+
+ if (encryptedDataObjects.hasNext()) {
+ var pgpPublicKeyEncryptedData = (PGPPublicKeyEncryptedData) encryptedDataObjects.next();
+ var pgpPrivateKey = retrievePgpPrivateKey(pgpPublicKeyEncryptedData);
+
+ return getByteArrayOutputStream(pgpPublicKeyEncryptedData, pgpPrivateKey);
+ } else {
+ throw new DataLengthException(String.format("No encrypted dataObjects found in file: %s", fileName));
+ }
+ }
+
+ private Iterator<PGPEncryptedData> getPgpEncryptedDataIterator(String fileName) throws IOException {
+ var secretDecoderStream = PGPUtil.getDecoderStream(KeyRetriever.getSecretKeyInputStream(fileName, dirPath));
+ var pgpObjectFactory = new PGPObjectFactory(secretDecoderStream, new BcKeyFingerprintCalculator());
+ var nextObject = pgpObjectFactory.nextObject();
+
+ return (nextObject instanceof PGPEncryptedDataList)
+ ? ((PGPEncryptedDataList) nextObject).getEncryptedDataObjects()
+ : ((PGPEncryptedDataList) pgpObjectFactory.nextObject()).getEncryptedDataObjects();
+ }
+
+ private PGPPrivateKey retrievePgpPrivateKey(PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData) throws IOException, PGPException {
+ var pgpPrivateKey = readSecretKey(new FileInputStream(secretFile), pgpPublicKeyEncryptedData.getKeyID())
+ .extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider())
+ .build(PasswordReader.getPassword()));
+
+ if (pgpPrivateKey == null) {
+ throw new IllegalArgumentException("Secret key for message not found.");
+ }
+
+ return pgpPrivateKey;
+ }
+
+ private PGPSecretKey readSecretKey(InputStream inputStream,
+ long keyId) throws IOException, PGPException {
+ inputStream = PGPUtil.getDecoderStream(inputStream);
+ var pgpSecretKeyRings = new PGPSecretKeyRingCollection(inputStream, new BcKeyFingerprintCalculator());
+ var secretKey = pgpSecretKeyRings.getSecretKey(keyId);
+
+ if (secretKey == null) {
+ throw new IllegalArgumentException("Can't find encryption key in key ring.");
+ }
+
+ return secretKey;
+ }
+
+ private byte[] getByteArrayOutputStream(PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData,
+ PGPPrivateKey pgpPrivateKey) throws IOException, PGPException {
+ ByteArrayOutputStream byteArrayOutputStream;
+
+ try (var dataStream = toDataStream(pgpPublicKeyEncryptedData, pgpPrivateKey)) {
+ byteArrayOutputStream = new ByteArrayOutputStream();
+ int dataRead;
+
+ while ((dataRead = dataStream.read()) >= 0) {
+ byteArrayOutputStream.write(dataRead);
+ }
+ }
+
+ return byteArrayOutputStream.toByteArray();
+ }
+
+ private InputStream toDataStream(PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData,
+ PGPPrivateKey pgpPrivateKey) throws PGPException, IOException {
+ var pgpDataStream = pgpPublicKeyEncryptedData.getDataStream(
+ new BcPublicKeyDataDecryptorFactory(pgpPrivateKey));
+ var jcaPGPObjectFactory = new JcaPGPObjectFactory(pgpDataStream);
+ var pgpCompressedDataStream = ((PGPCompressedData) jcaPGPObjectFactory.nextObject()).getDataStream();
+ jcaPGPObjectFactory = new JcaPGPObjectFactory(pgpCompressedDataStream);
+
+ return ((PGPLiteralData) jcaPGPObjectFactory.nextObject()).getDataStream();
+ }
+
+}
diff --git a/src/main/java/com/wimdupont/service/GpgUtil.java b/src/main/java/com/wimdupont/service/GpgUtil.java
@@ -1,117 +0,0 @@
-package com.wimdupont.service;
-
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openpgp.PGPCompressedData;
-import org.bouncycastle.openpgp.PGPEncryptedData;
-import org.bouncycastle.openpgp.PGPEncryptedDataList;
-import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPLiteralData;
-import org.bouncycastle.openpgp.PGPObjectFactory;
-import org.bouncycastle.openpgp.PGPPrivateKey;
-import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.bouncycastle.openpgp.PGPSecretKey;
-import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
-import org.bouncycastle.openpgp.PGPUtil;
-import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
-import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
-import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
-import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
-import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.Security;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.Properties;
-import java.util.Scanner;
-import java.util.stream.Collectors;
-
-public class GpgUtil {
-
- private final String dirPath;
- private final String secretFile;
- private static final String GPG_EXTENSION = ".gpg";
-
- public GpgUtil(Properties properties) {
- dirPath = properties.getProperty("dir.path");
- secretFile = properties.getProperty("secret.file");
- if (dirPath == null | secretFile == null)
- throw new RuntimeException("Properties missing.");
- }
-
- public byte[] decrypt(String fileArgument) throws IOException, PGPException {
- final Scanner scanner = new Scanner(System.in);
- File file;
- if (fileArgument != null) {
- file = new File(dirPath + fileArgument + GPG_EXTENSION).getAbsoluteFile();
- if (!file.exists()) throw new RuntimeException(String.format("File \"%s\" not found", file.getName()));
- } else {
- File[] files = new File(dirPath).listFiles();
- if (files == null || files.length < 1) throw new RuntimeException(dirPath + " contains no files");
- System.out.println("Which TOTP?");
- String fileNames = Arrays.stream(files)
- .filter(f -> f.getName().contains(GPG_EXTENSION))
- .map(f -> f.getName().replace(GPG_EXTENSION, ""))
- .collect(Collectors.joining(", "));
- System.out.println(fileNames);
- String fileName = scanner.nextLine();
- file = Arrays.stream(files).filter(f -> f.getName().replace(GPG_EXTENSION, "").equals(fileName)).findAny()
- .orElseThrow(() -> new RuntimeException("File not found"));
- }
-
- return decryptFile(new FileInputStream(file.getAbsolutePath()), PasswordReader.getPassword());
- }
-
- private PGPSecretKey readSecretKeyFromCol(InputStream in, long keyId) throws IOException, PGPException {
- in = PGPUtil.getDecoderStream(in);
- PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in, new BcKeyFingerprintCalculator());
- PGPSecretKey key = pgpSec.getSecretKey(keyId);
- if (key == null) {
- throw new IllegalArgumentException("Can't find encryption key in key ring.");
- }
- return key;
- }
-
- private byte[] decryptFile(InputStream in, char[] pass) throws IOException, PGPException {
- Security.addProvider(new BouncyCastleProvider());
- PGPSecretKey secKey;
- in = PGPUtil.getDecoderStream(in);
- JcaPGPObjectFactory pgpFact;
-
- PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator());
- Object o = pgpF.nextObject();
- PGPEncryptedDataList encList;
- if (o instanceof PGPEncryptedDataList) {
- encList = (PGPEncryptedDataList) o;
- } else {
- encList = (PGPEncryptedDataList) pgpF.nextObject();
- }
- Iterator<PGPEncryptedData> itt = encList.getEncryptedDataObjects();
- PGPPrivateKey sKey = null;
- PGPPublicKeyEncryptedData encP = null;
- while (sKey == null && itt.hasNext()) {
- encP = (PGPPublicKeyEncryptedData) itt.next();
- secKey = readSecretKeyFromCol(new FileInputStream(secretFile), encP.getKeyID());
- sKey = secKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass));
- }
- if (sKey == null) {
- throw new IllegalArgumentException("Secret key for message not found.");
- }
- InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
- pgpFact = new JcaPGPObjectFactory(clear);
- PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject();
- pgpFact = new JcaPGPObjectFactory(c1.getDataStream());
- PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- InputStream inLd = ld.getDataStream();
- int ch;
- while ((ch = inLd.read()) >= 0) {
- bOut.write(ch);
- }
- return bOut.toByteArray();
- }
-}
diff --git a/src/main/java/com/wimdupont/service/KeyRetriever.java b/src/main/java/com/wimdupont/service/KeyRetriever.java
@@ -0,0 +1,49 @@
+package com.wimdupont.service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Scanner;
+import java.util.stream.Collectors;
+
+public class KeyRetriever {
+
+ private static final String GPG_EXTENSION = ".gpg";
+
+ public static InputStream getSecretKeyInputStream(String fileArgument,
+ String dirPath) throws IOException {
+ var scanner = new Scanner(System.in);
+ File file;
+
+ if (fileArgument != null) {
+ file = new File(dirPath + fileArgument + GPG_EXTENSION).getAbsoluteFile();
+ if (!file.exists()) {
+ throw new FileNotFoundException(String.format("File \"%s\" not found", file.getName()));
+ }
+ } else {
+ var files = new File(dirPath).listFiles();
+ if (files == null || files.length < 1) {
+ throw new FileNotFoundException(dirPath + " contains no files");
+ }
+ String fileNames = Arrays.stream(files)
+ .filter(f -> f.getName().contains(GPG_EXTENSION))
+ .map(f -> f.getName().replace(GPG_EXTENSION, ""))
+ .collect(Collectors.joining(", "));
+
+ System.out.println("Which TOTP?");
+ System.out.println(fileNames);
+
+ String fileName = scanner.nextLine();
+
+ file = Arrays.stream(files)
+ .filter(f -> f.getName().replace(GPG_EXTENSION, "").equals(fileName))
+ .findAny()
+ .orElseThrow(() -> new FileNotFoundException("File not found"));
+ }
+
+ return new FileInputStream(file.getAbsolutePath());
+ }
+}
diff --git a/src/main/java/com/wimdupont/service/PasswordReader.java b/src/main/java/com/wimdupont/service/PasswordReader.java
@@ -22,17 +22,21 @@ public class PasswordReader {
}
private static char[] getPasswordByPanel(String prompt) {
- JPanel panel = new JPanel();
- final JPasswordField passwordField = new JPasswordField(10);
+ var panel = new JPanel();
+ var passwordField = new JPasswordField(10);
panel.add(new JLabel("Password"));
panel.add(passwordField);
- JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
+ var pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
@Override
public void selectInitialValue() {
passwordField.requestFocusInWindow();
}
};
- pane.createDialog(null, prompt).setVisible(true);
- return passwordField.getPassword().length == 0 ? new char[0] : passwordField.getPassword();
+ pane.createDialog(null, prompt)
+ .setVisible(true);
+
+ return passwordField.getPassword().length == 0
+ ? new char[0]
+ : passwordField.getPassword();
}
}
diff --git a/src/main/java/com/wimdupont/service/PropertiesLoader.java b/src/main/java/com/wimdupont/service/PropertiesLoader.java
@@ -1,22 +1,24 @@
package com.wimdupont.service;
import java.io.IOException;
-import java.io.InputStream;
import java.util.MissingResourceException;
import java.util.Properties;
public class PropertiesLoader {
public Properties loadProperties() {
- final Properties properties = new Properties();
- InputStream inputStream = getClass().getResourceAsStream("/application.properties");
+ final var properties = new Properties();
+ var inputStream = getClass().getResourceAsStream("/application.properties");
try {
if (inputStream == null) {
throw new IOException();
}
properties.load(inputStream);
} catch (IOException e) {
- throw new MissingResourceException("Missing application properties", Properties.class.getSimpleName(), "application.properties");
+ throw new MissingResourceException(
+ "Missing application properties",
+ Properties.class.getSimpleName(),
+ "application.properties");
}
return properties;
}
diff --git a/src/test/java/com/wimdupont/service/GpgServiceTest.java b/src/test/java/com/wimdupont/service/GpgServiceTest.java
@@ -0,0 +1,75 @@
+package com.wimdupont.service;
+
+
+import org.bouncycastle.openpgp.PGPException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+import static org.mockito.Mockito.mockStatic;
+
+public class GpgServiceTest {
+
+ private static final char[] PASSWORD = {'s', 'e', 'c', 'r', 'e', 't', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
+ private GpgService gpgService;
+
+ @BeforeEach
+ public void setup() {
+ var resourceDirectory = Paths.get("src", "test", "resources")
+ .toAbsolutePath()
+ .toString();
+ var properties = new Properties();
+
+ properties.setProperty("dir.path", String.format("%s/totpfiles/", resourceDirectory));
+ properties.setProperty("secret.file", String.format("%s/private-key.asc", resourceDirectory));
+
+ gpgService = new GpgService(properties);
+ }
+
+ @Test
+ public void decryptWithCorrectPasswordShouldReturnCorrectSecret() throws PGPException, IOException {
+ try (MockedStatic<PasswordReader> mocked = mockStatic(PasswordReader.class)) {
+ mocked.when(PasswordReader::getPassword).thenReturn(PASSWORD);
+
+ var result = gpgService.decrypt("encrypted-totp-secret");
+
+ Assertions.assertNotNull(result);
+ Assertions.assertEquals("This is the big secret key",
+ new String(result, Charset.defaultCharset()));
+ }
+ }
+
+ @Test
+ public void decryptWithWrongPasswordShouldThrowPgpException() {
+ try (MockedStatic<PasswordReader> mocked = mockStatic(PasswordReader.class)) {
+ mocked.when(PasswordReader::getPassword).thenReturn(new char[]{'w', 'r', 'o', 'n', 'g'});
+
+ Exception exception = Assertions.assertThrows(PGPException.class, () ->
+ gpgService.decrypt("encrypted-totp-secret")
+ );
+
+ Assertions.assertEquals(exception.getClass(), PGPException.class);
+ }
+ }
+
+ @Test
+ public void decryptUnknownFileShouldThrowException() {
+ try (MockedStatic<PasswordReader> mocked = mockStatic(PasswordReader.class)) {
+ mocked.when(PasswordReader::getPassword).thenReturn(PASSWORD);
+
+ Exception exception = Assertions.assertThrows(FileNotFoundException.class, () ->
+ gpgService.decrypt("unexisting")
+ );
+
+ Assertions.assertEquals(exception.getClass(), FileNotFoundException.class);
+ Assertions.assertEquals(exception.getMessage(), "File \"unexisting.gpg\" not found");
+ }
+ }
+}
+\ No newline at end of file
diff --git a/src/test/resources/private-key.asc b/src/test/resources/private-key.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lIYEZYasRRYJKwYBBAHaRw8BAQdATREN8PaSPOGDlP6ZjBM5Ws/U8qu1KelaLx6N
+EvEbU0z+BwMC6g7GBQQy+/X7KrmNSsP9wkSdBBbhgQx8C7TJdNtiRs8P7dX7p/CE
+ifpr5ivke7/Qjalo53GljWwYQCWelxL8hawYsOoXplv8XKWZ/l54sLQTVE9UUCBH
+ZW5lcmF0b3IgVGVzdIiTBBMWCgA7FiEE7p8C1GMJI6EaviAjtpe53CJEoPMFAmWG
+rEUCGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQtpe53CJEoPM3JgD8
+CsBls6FUiJiqsjstgdQ/QdANpuiRFoK3FJlmbgY6UzoA/0sBnCmazJHi/sjMjgu3
+xQugXhLHkdcvN3C24aeEs/gFnIsEZYasRRIKKwYBBAGXVQEFAQEHQCLZz+dcM5tC
+WQenmrF/M7dpyVDP6xHIFniFwGkTgkAYAwEIB/4HAwImuPNsGIOTIPsaEzShrd87
+IPh/seYzcgB/pL3vE6510CpsErmkanbvgGr+sLV5jUOl/BA2KK8zQaMdoZUttdDj
+vMFVEeeC1ddc3KwOjnn/iHgEGBYKACAWIQTunwLUYwkjoRq+ICO2l7ncIkSg8wUC
+ZYasRQIbDAAKCRC2l7ncIkSg8zUSAP0euvfg3iXWD9trkcVaUtrZ6FBpfslmOKnc
+v2JxzXlGZwEAgdm+ugRYRbS1iosIludyaSnUf+jlZtDOLGpSoF5nLQ8=
+=+tXU
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/src/test/resources/totpfiles/encrypted-totp-secret.gpg b/src/test/resources/totpfiles/encrypted-totp-secret.gpg
Binary files differ.