github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/go.crypto/openpgp/packet/ocfb.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9 6 7 package packet 8 9 import ( 10 "crypto/cipher" 11 ) 12 13 type ocfbEncrypter struct { 14 b cipher.Block 15 fre []byte 16 outUsed int 17 } 18 19 // An OCFBResyncOption determines if the "resynchronization step" of OCFB is 20 // performed. 21 type OCFBResyncOption bool 22 23 var ( 24 OCFBResync = OCFBResyncOption(true) 25 OCFBNoResync = OCFBResyncOption(false) 26 ) 27 28 // NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's 29 // cipher feedback mode using the given cipher.Block, and an initial amount of 30 // ciphertext. randData must be random bytes and be the same length as the 31 // cipher.Block's block size. Resync determines if the "resynchronization step" 32 // from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on 33 // this point. 34 func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) { 35 blockSize := block.BlockSize() 36 if len(randData) != blockSize { 37 return nil, nil 38 } 39 40 x := &ocfbEncrypter{ 41 b: block, 42 fre: make([]byte, blockSize), 43 outUsed: 0, 44 } 45 prefix := make([]byte, blockSize+2) 46 47 block.Encrypt(x.fre, x.fre) 48 for i := 0; i < blockSize; i++ { 49 prefix[i] = randData[i] ^ x.fre[i] 50 } 51 52 block.Encrypt(x.fre, prefix[:blockSize]) 53 prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] 54 prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] 55 56 if resync { 57 block.Encrypt(x.fre, prefix[2:]) 58 } else { 59 x.fre[0] = prefix[blockSize] 60 x.fre[1] = prefix[blockSize+1] 61 x.outUsed = 2 62 } 63 return x, prefix 64 } 65 66 func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) { 67 for i := 0; i < len(src); i++ { 68 if x.outUsed == len(x.fre) { 69 x.b.Encrypt(x.fre, x.fre) 70 x.outUsed = 0 71 } 72 73 x.fre[x.outUsed] ^= src[i] 74 dst[i] = x.fre[x.outUsed] 75 x.outUsed++ 76 } 77 } 78 79 type ocfbDecrypter struct { 80 b cipher.Block 81 fre []byte 82 outUsed int 83 } 84 85 // NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's 86 // cipher feedback mode using the given cipher.Block. Prefix must be the first 87 // blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's 88 // block size. If an incorrect key is detected then nil is returned. On 89 // successful exit, blockSize+2 bytes of decrypted data are written into 90 // prefix. Resync determines if the "resynchronization step" from RFC 4880, 91 // 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. 92 func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { 93 blockSize := block.BlockSize() 94 if len(prefix) != blockSize+2 { 95 return nil 96 } 97 98 x := &ocfbDecrypter{ 99 b: block, 100 fre: make([]byte, blockSize), 101 outUsed: 0, 102 } 103 prefixCopy := make([]byte, len(prefix)) 104 copy(prefixCopy, prefix) 105 106 block.Encrypt(x.fre, x.fre) 107 for i := 0; i < blockSize; i++ { 108 prefixCopy[i] ^= x.fre[i] 109 } 110 111 block.Encrypt(x.fre, prefix[:blockSize]) 112 prefixCopy[blockSize] ^= x.fre[0] 113 prefixCopy[blockSize+1] ^= x.fre[1] 114 115 if prefixCopy[blockSize-2] != prefixCopy[blockSize] || 116 prefixCopy[blockSize-1] != prefixCopy[blockSize+1] { 117 return nil 118 } 119 120 if resync { 121 block.Encrypt(x.fre, prefix[2:]) 122 } else { 123 x.fre[0] = prefix[blockSize] 124 x.fre[1] = prefix[blockSize+1] 125 x.outUsed = 2 126 } 127 copy(prefix, prefixCopy) 128 return x 129 } 130 131 func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) { 132 for i := 0; i < len(src); i++ { 133 if x.outUsed == len(x.fre) { 134 x.b.Encrypt(x.fre, x.fre) 135 x.outUsed = 0 136 } 137 138 c := src[i] 139 dst[i] = x.fre[x.outUsed] ^ src[i] 140 x.fre[x.outUsed] = c 141 x.outUsed++ 142 } 143 }