82 lines
3.2 KiB
Kotlin
82 lines
3.2 KiB
Kotlin
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package org.pgpainless.sop
|
|
|
|
import java.io.IOException
|
|
import java.io.InputStream
|
|
import java.io.OutputStream
|
|
import org.bouncycastle.openpgp.PGPException
|
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection
|
|
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
|
|
import org.pgpainless.exception.MissingPassphraseException
|
|
import org.pgpainless.key.protection.SecretKeyRingProtector
|
|
import org.pgpainless.key.util.KeyRingUtils
|
|
import org.pgpainless.util.ArmoredOutputStreamFactory
|
|
import org.pgpainless.util.Passphrase
|
|
import sop.Ready
|
|
import sop.exception.SOPGPException
|
|
import sop.operation.ChangeKeyPassword
|
|
|
|
/** Implementation of the `change-key-password` operation using PGPainless. */
|
|
class ChangeKeyPasswordImpl : ChangeKeyPassword {
|
|
|
|
private val oldProtector = MatchMakingSecretKeyRingProtector()
|
|
private var newPassphrase = Passphrase.emptyPassphrase()
|
|
private var armor = true
|
|
|
|
override fun keys(keys: InputStream): Ready {
|
|
val newProtector = SecretKeyRingProtector.unlockAnyKeyWith(newPassphrase)
|
|
val secretKeysCollection =
|
|
try {
|
|
KeyReader.readSecretKeys(keys, true)
|
|
} catch (e: IOException) {
|
|
throw SOPGPException.BadData(e)
|
|
}
|
|
|
|
val updatedSecretKeys =
|
|
secretKeysCollection
|
|
.map { secretKeys ->
|
|
oldProtector.addSecretKey(secretKeys)
|
|
try {
|
|
return@map KeyRingUtils.changePassphrase(
|
|
null, secretKeys, oldProtector, newProtector)
|
|
} catch (e: MissingPassphraseException) {
|
|
throw SOPGPException.KeyIsProtected(
|
|
"Cannot unlock key ${secretKeys.openPgpFingerprint}", e)
|
|
} catch (e: PGPException) {
|
|
if (e.message?.contains("Exception decrypting key") == true) {
|
|
throw SOPGPException.KeyIsProtected(
|
|
"Cannot unlock key ${secretKeys.openPgpFingerprint}", e)
|
|
}
|
|
throw RuntimeException(
|
|
"Cannot change passphrase of key ${secretKeys.openPgpFingerprint}", e)
|
|
}
|
|
}
|
|
.let { PGPSecretKeyRingCollection(it) }
|
|
|
|
return object : Ready() {
|
|
override fun writeTo(outputStream: OutputStream) {
|
|
if (armor) {
|
|
ArmoredOutputStreamFactory.get(outputStream).use {
|
|
updatedSecretKeys.encode(it)
|
|
}
|
|
} else {
|
|
updatedSecretKeys.encode(outputStream)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun newKeyPassphrase(newPassphrase: String): ChangeKeyPassword = apply {
|
|
this.newPassphrase = Passphrase.fromPassword(newPassphrase)
|
|
}
|
|
|
|
override fun noArmor(): ChangeKeyPassword = apply { armor = false }
|
|
|
|
override fun oldKeyPassphrase(oldPassphrase: String): ChangeKeyPassword = apply {
|
|
oldProtector.addPassphrase(Passphrase.fromPassword(oldPassphrase))
|
|
}
|
|
}
|