github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/test/chaincodes/AuctionApp/image_proc_api.go (about)

     1  /******************************************************************
     2  Copyright IT People Corp. 2017 All Rights Reserved.
     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  
    18  ///////////////////////////////////////////////////////////////////////
    19  // Author : IT People - Mohan Venkataraman - image API
    20  // Purpose: Explore the Hyperledger/fabric and understand
    21  // how to write an chain code, application/chain code boundaries
    22  // The code is not the best as it has just hammered out in a day or two
    23  // Feedback and updates are appreciated
    24  ///////////////////////////////////////////////////////////////////////
    25  
    26  package main
    27  
    28  import (
    29  	"bufio"
    30  	"bytes"
    31  	"crypto/aes"
    32  	"crypto/cipher"
    33  	"crypto/rand"
    34  	"errors"
    35  	"fmt"
    36  	"image"
    37  	"image/gif"
    38  	"image/jpeg"
    39  	"image/png"
    40  	"io"
    41  	"net/http"
    42  	"os"
    43  )
    44  
    45  ///////////////////////////////////////////////////////////
    46  // Convert Image to []bytes and viceversa
    47  // Detect Image Filetype
    48  // Image Function to read an image and create a byte array
    49  // Currently only PNG images are supported
    50  ///////////////////////////////////////////////////////////
    51  func ImageToByteArray(imageFile string) ([]byte, string) {
    52  
    53  	file, err := os.Open(imageFile)
    54  
    55  	if err != nil {
    56  		fmt.Println("imageToByteArray() : cannot OPEN image file ", err)
    57  		return nil, string("imageToByteArray() : cannot OPEN image file ")
    58  	}
    59  
    60  	defer file.Close()
    61  
    62  	fileInfo, _ := file.Stat()
    63  	var size int64 = fileInfo.Size()
    64  	bytes := make([]byte, size)
    65  
    66  	// read file into bytes
    67  	buff := bufio.NewReader(file)
    68  	_, err = buff.Read(bytes)
    69  
    70  	if err != nil {
    71  		fmt.Println("imageToByteArray() : cannot READ image file")
    72  		return nil, string("imageToByteArray() : cannot READ image file ")
    73  	}
    74  
    75  	filetype := http.DetectContentType(bytes)
    76  	fmt.Println("imageToByteArray() : ", filetype)
    77  	//filetype := GetImageType(bytes)
    78  
    79  	return bytes, filetype
    80  }
    81  
    82  //////////////////////////////////////////////////////
    83  // If Valid fileType, will have "image" as first word
    84  //////////////////////////////////////////////////////
    85  func GetImageType(buff []byte) string {
    86  	filetype := http.DetectContentType(buff)
    87  
    88  	switch filetype {
    89  	case "image/jpeg", "image/jpg":
    90  		return filetype
    91  
    92  	case "image/gif":
    93  		return filetype
    94  
    95  	case "image/png":
    96  		return filetype
    97  
    98  	case "application/pdf": // not image, but application !
    99  		filetype = "application/pdf"
   100  	default:
   101  		filetype = "Unknown"
   102  	}
   103  	return filetype
   104  }
   105  
   106  ////////////////////////////////////////////////////////////
   107  // Converts a byteArray into an image and saves it
   108  // into an appropriate file
   109  // It is important to get the file type before saving the
   110  // file by call the GetImageType
   111  ////////////////////////////////////////////////////////////
   112  func ByteArrayToImage(imgByte []byte, imageFile string) error {
   113  
   114  	// convert []byte to image for saving to file
   115  	img, _, _ := image.Decode(bytes.NewReader(imgByte))
   116  
   117  	fmt.Println("ProcessQueryResult ByteArrayToImage : proceeding to create image ")
   118  
   119  	//save the imgByte to file
   120  	out, err := os.Create(imageFile)
   121  
   122  	if err != nil {
   123  		fmt.Println("ByteArrayToImage() : cannot CREATE image file ", err)
   124  		return errors.New("ByteArrayToImage() : cannot CREATE image file ")
   125  	}
   126  	fmt.Println("ProcessRequestType ByteArrayToImage : proceeding to Encode image ")
   127  
   128  	//err = png.Encode(out, img)
   129  	filetype := http.DetectContentType(imgByte)
   130  
   131  	switch filetype {
   132  	case "image/jpeg", "image/jpg":
   133  		var opt jpeg.Options
   134  		opt.Quality = 100
   135  		err = jpeg.Encode(out, img, &opt)
   136  
   137  	case "image/gif":
   138  		var opt gif.Options
   139  		opt.NumColors = 256
   140  		err = gif.Encode(out, img, &opt)
   141  
   142  	case "image/png":
   143  		err = png.Encode(out, img)
   144  
   145  	default:
   146  		err = errors.New("Only PMNG, JPG and GIF Supported ")
   147  	}
   148  
   149  	if err != nil {
   150  		fmt.Println("ByteArrayToImage() : cannot ENCODE image file ", err)
   151  		return errors.New("ByteArrayToImage() : cannot ENCODE image file ")
   152  	}
   153  
   154  	// everything ok
   155  	fmt.Println("Image file  generated and saved to ", imageFile)
   156  	return nil
   157  }
   158  
   159  ///////////////////////////////////////////////////////////////////////
   160  // Encryption and Decryption Section
   161  // Images will be Encrypted and stored and the key will be part of the
   162  // certificate that is provided to the Owner
   163  ///////////////////////////////////////////////////////////////////////
   164  
   165  const (
   166  	AESKeyLength = 32 // AESKeyLength is the default AES key length
   167  	NonceSize    = 24 // NonceSize is the default NonceSize
   168  )
   169  
   170  ///////////////////////////////////////////////////
   171  // GetRandomBytes returns len random looking bytes
   172  ///////////////////////////////////////////////////
   173  func GetRandomBytes(len int) ([]byte, error) {
   174  	key := make([]byte, len)
   175  
   176  	_, err := rand.Read(key)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	return key, nil
   182  }
   183  
   184  ////////////////////////////////////////////////////////////
   185  // GenAESKey returns a random AES key of length AESKeyLength
   186  // 3 Functions to support Encryption and Decryption
   187  // GENAESKey() - Generates AES symmetric key
   188  // Encrypt() Encrypts a [] byte
   189  // Decrypt() Decryts a [] byte
   190  ////////////////////////////////////////////////////////////
   191  func GenAESKey() ([]byte, error) {
   192  	return GetRandomBytes(AESKeyLength)
   193  }
   194  
   195  func PKCS5Pad(src []byte) []byte {
   196  	padding := aes.BlockSize - len(src)%aes.BlockSize
   197  	pad := bytes.Repeat([]byte{byte(padding)}, padding)
   198  	return append(src, pad...)
   199  }
   200  
   201  func PKCS5Unpad(src []byte) []byte {
   202  	len := len(src)
   203  	unpad := int(src[len-1])
   204  	return src[:(len - unpad)]
   205  }
   206  
   207  func Decrypt(key []byte, ciphertext []byte) []byte {
   208  
   209  	// Create the AES cipher
   210  	block, err := aes.NewCipher(key)
   211  	if err != nil {
   212  		panic(err)
   213  	}
   214  
   215  	// Before even testing the decryption,
   216  	// if the text is too small, then it is incorrect
   217  	if len(ciphertext) < aes.BlockSize {
   218  		panic("Text is too short")
   219  	}
   220  
   221  	// Get the 16 byte IV
   222  	iv := ciphertext[:aes.BlockSize]
   223  
   224  	// Remove the IV from the ciphertext
   225  	ciphertext = ciphertext[aes.BlockSize:]
   226  
   227  	// Return a decrypted stream
   228  	stream := cipher.NewCFBDecrypter(block, iv)
   229  
   230  	// Decrypt bytes from ciphertext
   231  	stream.XORKeyStream(ciphertext, ciphertext)
   232  
   233  	return ciphertext
   234  }
   235  
   236  func Encrypt(key []byte, ba []byte) []byte {
   237  
   238  	// Create the AES cipher
   239  	block, err := aes.NewCipher(key)
   240  	if err != nil {
   241  		panic(err)
   242  	}
   243  
   244  	// Empty array of 16 + ba length
   245  	// Include the IV at the beginning
   246  	ciphertext := make([]byte, aes.BlockSize+len(ba))
   247  
   248  	// Slice of first 16 bytes
   249  	iv := ciphertext[:aes.BlockSize]
   250  
   251  	// Write 16 rand bytes to fill iv
   252  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
   253  		panic(err)
   254  	}
   255  
   256  	// Return an encrypted stream
   257  	stream := cipher.NewCFBEncrypter(block, iv)
   258  
   259  	// Encrypt bytes from ba to ciphertext
   260  	stream.XORKeyStream(ciphertext[aes.BlockSize:], ba)
   261  
   262  	return ciphertext
   263  }