github.com/readium/readium-lcp-server@v0.0.0-20240101192032-6e95190e99f1/crypto/aes_cbc.go (about) 1 // Copyright (c) 2016 Readium Foundation 2 // 3 // Redistribution and use in source and binary forms, with or without modification, 4 // are permitted provided that the following conditions are met: 5 // 6 // 1. Redistributions of source code must retain the above copyright notice, this 7 // list of conditions and the following disclaimer. 8 // 2. Redistributions in binary form must reproduce the above copyright notice, 9 // this list of conditions and the following disclaimer in the documentation and/or 10 // other materials provided with the distribution. 11 // 3. Neither the name of the organization nor the names of its contributors may be 12 // used to endorse or promote products derived from this software without specific 13 // prior written permission 14 // 15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26 package crypto 27 28 import ( 29 "bytes" 30 "crypto/aes" 31 "crypto/cipher" 32 "crypto/rand" 33 "io" 34 ) 35 36 type cbcEncrypter struct{} 37 38 const ( 39 aes256keyLength = 32 // 256 bits 40 ) 41 42 func (e cbcEncrypter) Signature() string { 43 // W3C padding scheme, not PKCS#7 (see last parameter "insertPadLengthAll" [false] of PaddedReader constructor) 44 return "http://www.w3.org/2001/04/xmlenc#aes256-cbc" 45 } 46 47 func (e cbcEncrypter) GenerateKey() (ContentKey, error) { 48 slice, err := GenerateKey(aes256keyLength) 49 return ContentKey(slice), err 50 } 51 52 func (e cbcEncrypter) Encrypt(key ContentKey, r io.Reader, w io.Writer) error { 53 54 r = PaddedReader(r, aes.BlockSize, false) 55 56 block, err := aes.NewCipher(key) 57 if err != nil { 58 return err 59 } 60 61 // generate the IV 62 iv := make([]byte, aes.BlockSize) 63 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 64 return err 65 } 66 67 // write the IV first 68 if _, err = w.Write(iv); err != nil { 69 return err 70 } 71 72 mode := cipher.NewCBCEncrypter(block, iv) 73 buffer := make([]byte, aes.BlockSize) 74 for _, err = io.ReadFull(r, buffer); err == nil; _, err = io.ReadFull(r, buffer) { 75 mode.CryptBlocks(buffer, buffer) 76 _, wErr := w.Write(buffer) 77 if wErr != nil { 78 return wErr 79 } 80 } 81 82 if err == nil || err == io.EOF { 83 return nil 84 } 85 86 return err 87 } 88 89 func (c cbcEncrypter) Decrypt(key ContentKey, r io.Reader, w io.Writer) error { 90 block, err := aes.NewCipher(key) 91 if err != nil { 92 return err 93 } 94 95 var buffer bytes.Buffer 96 io.Copy(&buffer, r) 97 98 buf := buffer.Bytes() 99 iv := buf[:aes.BlockSize] 100 101 mode := cipher.NewCBCDecrypter(block, iv) 102 mode.CryptBlocks(buf[aes.BlockSize:], buf[aes.BlockSize:]) 103 104 padding := buf[len(buf)-1] // padding length valid for both PKCS#7 and W3C schemes 105 w.Write(buf[aes.BlockSize : len(buf)-int(padding)]) 106 107 return nil 108 } 109 110 func NewAESCBCEncrypter() Encrypter { 111 return cbcEncrypter(struct{}{}) 112 }