github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/crypto.go (about)

     1  /*
     2  	Copyright 2020 The pdfcpu Authors.
     3  
     4  	Licensed under the Apache License, Version 2.0 (the "License");
     5  	you may not use this file except in compliance with the License.
     6  	You may obtain a copy of the License at
     7  
     8  		http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  	Unless required by applicable law or agreed to in writing, software
    11  	distributed under the License is distributed on an "AS IS" BASIS,
    12  	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  	See the License for the specific language governing permissions and
    14  	limitations under the License.
    15  */
    16  
    17  package api
    18  
    19  import (
    20  	"io"
    21  	"os"
    22  
    23  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  // Encrypt reads a PDF stream from rs and writes the encrypted PDF stream to w.
    28  // A configuration containing at least the current passwords is required.
    29  func Encrypt(rs io.ReadSeeker, w io.Writer, conf *model.Configuration) error {
    30  	if rs == nil {
    31  		return errors.New("pdfcpu: Encrypt: missing rs")
    32  	}
    33  
    34  	if conf == nil {
    35  		return errors.New("pdfcpu: missing configuration for encryption")
    36  	}
    37  	conf.Cmd = model.ENCRYPT
    38  
    39  	return Optimize(rs, w, conf)
    40  }
    41  
    42  // EncryptFile encrypts inFile and writes the result to outFile.
    43  // A configuration containing at least the current passwords is required.
    44  func EncryptFile(inFile, outFile string, conf *model.Configuration) (err error) {
    45  	if conf == nil {
    46  		return errors.New("pdfcpu: missing configuration for encryption")
    47  	}
    48  	conf.Cmd = model.ENCRYPT
    49  
    50  	var f1, f2 *os.File
    51  
    52  	if f1, err = os.Open(inFile); err != nil {
    53  		return err
    54  	}
    55  
    56  	tmpFile := inFile + ".tmp"
    57  	if outFile != "" && inFile != outFile {
    58  		tmpFile = outFile
    59  		logWritingTo(outFile)
    60  	} else {
    61  		logWritingTo(inFile)
    62  	}
    63  
    64  	if f2, err = os.Create(tmpFile); err != nil {
    65  		f1.Close()
    66  		return err
    67  	}
    68  
    69  	defer func() {
    70  		if err != nil {
    71  			f2.Close()
    72  			f1.Close()
    73  			os.Remove(tmpFile)
    74  			return
    75  		}
    76  		if err = f2.Close(); err != nil {
    77  			return
    78  		}
    79  		if err = f1.Close(); err != nil {
    80  			return
    81  		}
    82  		if outFile == "" || inFile == outFile {
    83  			err = os.Rename(tmpFile, inFile)
    84  		}
    85  	}()
    86  
    87  	return Encrypt(f1, f2, conf)
    88  }
    89  
    90  // Decrypt reads a PDF stream from rs and writes the encrypted PDF stream to w.
    91  // A configuration containing at least the current passwords is required.
    92  func Decrypt(rs io.ReadSeeker, w io.Writer, conf *model.Configuration) error {
    93  	if rs == nil {
    94  		return errors.New("pdfcpu: Decrypt: missing rs")
    95  	}
    96  
    97  	if conf == nil {
    98  		return errors.New("pdfcpu: missing configuration for decryption")
    99  	}
   100  	conf.Cmd = model.DECRYPT
   101  
   102  	return Optimize(rs, w, conf)
   103  }
   104  
   105  // DecryptFile decrypts inFile and writes the result to outFile.
   106  // A configuration containing at least the current passwords is required.
   107  func DecryptFile(inFile, outFile string, conf *model.Configuration) (err error) {
   108  	if conf == nil {
   109  		return errors.New("pdfcpu: missing configuration for decryption")
   110  	}
   111  	conf.Cmd = model.DECRYPT
   112  
   113  	var f1, f2 *os.File
   114  
   115  	if f1, err = os.Open(inFile); err != nil {
   116  		return err
   117  	}
   118  
   119  	tmpFile := inFile + ".tmp"
   120  	if outFile != "" && inFile != outFile {
   121  		tmpFile = outFile
   122  		logWritingTo(outFile)
   123  	} else {
   124  		logWritingTo(inFile)
   125  	}
   126  
   127  	if f2, err = os.Create(tmpFile); err != nil {
   128  		f1.Close()
   129  		return err
   130  	}
   131  
   132  	defer func() {
   133  		if err != nil {
   134  			f2.Close()
   135  			f1.Close()
   136  			os.Remove(tmpFile)
   137  			return
   138  		}
   139  		if err = f2.Close(); err != nil {
   140  			return
   141  		}
   142  		if err = f1.Close(); err != nil {
   143  			return
   144  		}
   145  		if outFile == "" || inFile == outFile {
   146  			err = os.Rename(tmpFile, inFile)
   147  		}
   148  	}()
   149  
   150  	return Decrypt(f1, f2, conf)
   151  }
   152  
   153  // ChangeUserPassword reads a PDF stream from rs, changes the user password and writes the encrypted PDF stream to w.
   154  // A configuration containing the current passwords is required.
   155  func ChangeUserPassword(rs io.ReadSeeker, w io.Writer, pwOld, pwNew string, conf *model.Configuration) error {
   156  	if rs == nil {
   157  		return errors.New("pdfcpu: ChangeUserPassword: missing rs")
   158  	}
   159  
   160  	if conf == nil {
   161  		return errors.New("pdfcpu: missing configuration for change user password")
   162  	}
   163  
   164  	conf.Cmd = model.CHANGEUPW
   165  	conf.UserPW = pwOld
   166  	conf.UserPWNew = &pwNew
   167  
   168  	return Optimize(rs, w, conf)
   169  }
   170  
   171  // ChangeUserPasswordFile reads inFile, changes the user password and writes the result to outFile.
   172  // A configuration containing the current passwords is required.
   173  func ChangeUserPasswordFile(inFile, outFile string, pwOld, pwNew string, conf *model.Configuration) (err error) {
   174  	if conf == nil {
   175  		return errors.New("pdfcpu: missing configuration for change user password")
   176  	}
   177  
   178  	conf.Cmd = model.CHANGEUPW
   179  	conf.UserPW = pwOld
   180  	conf.UserPWNew = &pwNew
   181  
   182  	var f1, f2 *os.File
   183  
   184  	if f1, err = os.Open(inFile); err != nil {
   185  		return err
   186  	}
   187  
   188  	tmpFile := inFile + ".tmp"
   189  	if outFile != "" && inFile != outFile {
   190  		tmpFile = outFile
   191  		logWritingTo(outFile)
   192  	} else {
   193  		logWritingTo(inFile)
   194  	}
   195  
   196  	if f2, err = os.Create(tmpFile); err != nil {
   197  		f1.Close()
   198  		return err
   199  	}
   200  
   201  	defer func() {
   202  		if err != nil {
   203  			f2.Close()
   204  			f1.Close()
   205  			os.Remove(tmpFile)
   206  			return
   207  		}
   208  		if err = f2.Close(); err != nil {
   209  			return
   210  		}
   211  		if err = f1.Close(); err != nil {
   212  			return
   213  		}
   214  		if outFile == "" || inFile == outFile {
   215  			err = os.Rename(tmpFile, inFile)
   216  		}
   217  	}()
   218  
   219  	return ChangeUserPassword(f1, f2, pwOld, pwNew, conf)
   220  }
   221  
   222  // ChangeOwnerPassword reads a PDF stream from rs, changes the owner password and writes the encrypted PDF stream to w.
   223  // A configuration containing the current passwords is required.
   224  func ChangeOwnerPassword(rs io.ReadSeeker, w io.Writer, pwOld, pwNew string, conf *model.Configuration) error {
   225  	if rs == nil {
   226  		return errors.New("pdfcpu: ChangeOwnerPassword: missing rs")
   227  	}
   228  
   229  	if conf == nil {
   230  		return errors.New("pdfcpu: missing configuration for change owner password")
   231  	}
   232  
   233  	conf.Cmd = model.CHANGEOPW
   234  	conf.OwnerPW = pwOld
   235  	conf.OwnerPWNew = &pwNew
   236  
   237  	return Optimize(rs, w, conf)
   238  }
   239  
   240  // ChangeOwnerPasswordFile reads inFile, changes the owner password and writes the result to outFile.
   241  // A configuration containing the current passwords is required.
   242  func ChangeOwnerPasswordFile(inFile, outFile string, pwOld, pwNew string, conf *model.Configuration) (err error) {
   243  	if conf == nil {
   244  		return errors.New("pdfcpu: missing configuration for change owner password")
   245  	}
   246  	conf.Cmd = model.CHANGEOPW
   247  	conf.OwnerPW = pwOld
   248  	conf.OwnerPWNew = &pwNew
   249  
   250  	var f1, f2 *os.File
   251  
   252  	if f1, err = os.Open(inFile); err != nil {
   253  		return err
   254  	}
   255  
   256  	tmpFile := inFile + ".tmp"
   257  	if outFile != "" && inFile != outFile {
   258  		tmpFile = outFile
   259  		logWritingTo(outFile)
   260  	} else {
   261  		logWritingTo(inFile)
   262  	}
   263  
   264  	if f2, err = os.Create(tmpFile); err != nil {
   265  		return err
   266  	}
   267  
   268  	defer func() {
   269  		if err != nil {
   270  			f2.Close()
   271  			f1.Close()
   272  			os.Remove(tmpFile)
   273  			return
   274  		}
   275  		if err = f2.Close(); err != nil {
   276  			return
   277  		}
   278  		if err = f1.Close(); err != nil {
   279  			return
   280  		}
   281  		if outFile == "" || inFile == outFile {
   282  			err = os.Rename(tmpFile, inFile)
   283  		}
   284  	}()
   285  
   286  	return ChangeOwnerPassword(f1, f2, pwOld, pwNew, conf)
   287  }