2020-12-16 20:09:01 +01:00
/ *
* Copyright 2020 Paul Schaub .
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2020-11-26 11:00:48 +01:00
package org.pgpainless.sop.commands ;
import org.bouncycastle.openpgp.PGPException ;
import org.bouncycastle.openpgp.PGPSecretKeyRing ;
import org.bouncycastle.openpgp.PGPSignature ;
import org.bouncycastle.util.io.Streams ;
import org.pgpainless.PGPainless ;
2021-05-20 13:42:52 +02:00
import org.pgpainless.algorithm.DocumentSignatureType ;
import org.pgpainless.encryption_signing.EncryptionResult ;
2020-11-26 11:00:48 +01:00
import org.pgpainless.encryption_signing.EncryptionStream ;
2021-05-20 13:42:52 +02:00
import org.pgpainless.encryption_signing.ProducerOptions ;
import org.pgpainless.encryption_signing.SigningOptions ;
import org.pgpainless.key.SubkeyIdentifier ;
import org.pgpainless.key.protection.SecretKeyRingProtector ;
2020-11-26 11:00:48 +01:00
import org.pgpainless.sop.Print ;
import picocli.CommandLine ;
2020-12-22 22:08:38 +01:00
import java.io.ByteArrayOutputStream ;
import java.io.File ;
import java.io.FileInputStream ;
import java.io.IOException ;
2020-12-16 20:09:01 +01:00
import static org.pgpainless.sop.Print.err_ln ;
import static org.pgpainless.sop.Print.print_ln ;
2020-12-22 23:07:53 +01:00
@CommandLine.Command ( name = " sign " ,
2021-03-05 14:15:54 +01:00
description = " Create a detached signature on the data from standard input " ,
exitCodeOnInvalidInput = 37 )
2020-11-26 11:00:48 +01:00
public class Sign implements Runnable {
public enum Type {
binary ,
text
}
2020-12-22 22:05:47 +01:00
@CommandLine.Option ( names = " --no-armor " ,
description = " ASCII armor the output " ,
negatable = true )
boolean armor = true ;
2020-11-26 11:00:48 +01:00
2020-12-16 20:09:01 +01:00
@CommandLine.Option ( names = " --as " , description = " Defaults to 'binary'. If '--as=text' and the input data is not valid UTF-8, sign fails with return code 53. " ,
2020-12-22 22:08:38 +01:00
paramLabel = " {binary|text} " )
2020-11-26 11:00:48 +01:00
Type type ;
2020-12-22 22:08:38 +01:00
@CommandLine.Parameters ( description = " Secret keys used for signing " ,
paramLabel = " KEY " ,
arity = " 1..* " )
File [ ] secretKeyFile ;
2020-11-26 11:00:48 +01:00
@Override
public void run ( ) {
2020-12-22 22:08:38 +01:00
PGPSecretKeyRing [ ] secretKeys = new PGPSecretKeyRing [ secretKeyFile . length ] ;
for ( int i = 0 , secretKeyFileLength = secretKeyFile . length ; i < secretKeyFileLength ; i + + ) {
File file = secretKeyFile [ i ] ;
try {
PGPSecretKeyRing secretKey = PGPainless . readKeyRing ( ) . secretKeyRing ( new FileInputStream ( file ) ) ;
secretKeys [ i ] = secretKey ;
} catch ( IOException | PGPException e ) {
err_ln ( " Error reading secret key ring " + file . getName ( ) ) ;
err_ln ( e . getMessage ( ) ) ;
System . exit ( 1 ) ;
return ;
}
2020-11-26 11:00:48 +01:00
}
try {
2021-05-20 13:42:52 +02:00
SigningOptions signOpt = new SigningOptions ( ) ;
for ( PGPSecretKeyRing signingKey : secretKeys ) {
signOpt . addDetachedSignature ( SecretKeyRingProtector . unprotectedKeys ( ) , signingKey ,
type = = Type . text ? DocumentSignatureType . CANONICAL_TEXT_DOCUMENT : DocumentSignatureType . BINARY_DOCUMENT ) ;
}
2020-12-16 16:43:58 +01:00
ByteArrayOutputStream out = new ByteArrayOutputStream ( ) ;
2021-05-20 13:42:52 +02:00
EncryptionStream encryptionStream = PGPainless . encryptAndOrSign ( )
. onOutputStream ( out )
. withOptions ( ProducerOptions
. sign ( signOpt )
. setAsciiArmor ( armor ) ) ;
2020-11-26 11:00:48 +01:00
Streams . pipeAll ( System . in , encryptionStream ) ;
encryptionStream . close ( ) ;
2021-05-20 13:42:52 +02:00
EncryptionResult result = encryptionStream . getResult ( ) ;
for ( SubkeyIdentifier signingKey : result . getDetachedSignatures ( ) . keySet ( ) ) {
for ( PGPSignature signature : result . getDetachedSignatures ( ) . get ( signingKey ) ) {
print_ln ( Print . toString ( signature . getEncoded ( ) , armor ) ) ;
}
}
2020-11-26 11:00:48 +01:00
} catch ( PGPException | IOException e ) {
2020-12-16 20:09:01 +01:00
err_ln ( " Error signing data. " ) ;
err_ln ( e . getMessage ( ) ) ;
2020-11-26 11:00:48 +01:00
System . exit ( 1 ) ;
}
}
}