{"id":21974304,"url":"https://github.com/5olitude/aes_ecb-decoder","last_synced_at":"2025-07-09T23:15:18.049Z","repository":{"id":258849267,"uuid":"875559959","full_name":"5olitude/AES_ECB-DECODER","owner":"5olitude","description":"Example of decoding (AES With ECB) encrypted image in golang.","archived":false,"fork":false,"pushed_at":"2024-10-20T20:59:45.000Z","size":62,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-29T15:52:47.597Z","etag":null,"topics":["aes","aes-encryption","bmp","decrypt","ecb","ecb-mode"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/5olitude.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-20T10:08:52.000Z","updated_at":"2024-10-20T20:59:49.000Z","dependencies_parsed_at":"2024-10-21T01:28:05.492Z","dependency_job_id":null,"html_url":"https://github.com/5olitude/AES_ECB-DECODER","commit_stats":null,"previous_names":["5olitude/aes_ecb-decoder"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5olitude%2FAES_ECB-DECODER","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5olitude%2FAES_ECB-DECODER/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5olitude%2FAES_ECB-DECODER/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/5olitude%2FAES_ECB-DECODER/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/5olitude","download_url":"https://codeload.github.com/5olitude/AES_ECB-DECODER/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235955898,"owners_count":19071963,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes","aes-encryption","bmp","decrypt","ecb","ecb-mode"],"created_at":"2024-11-29T15:40:55.859Z","updated_at":"2025-01-28T03:17:26.208Z","avatar_url":"https://github.com/5olitude.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **AES ECB Decoder in Go**\n\nAn example of decoding an image encrypted using **AES** in **ECB** (Electronic Codebook) mode with **Go**. This demonstrates how AES-ECB works and explains why it's considered insecure for real-world usage.\n\n## **What is AES with ECB Encryption?**\n\n**AES** (Advanced Encryption Standard) is a symmetric block cipher that encrypts data in blocks.  \nThe AES block size is always **128 bits**, which is equal to **16 bytes**.\n\n### **Process in Each Round:**\n\nEach encryption round in AES involves the following steps:\n\n1. **SubBytes**: A non-linear substitution step where each byte in the block is replaced using a substitution table (S-box).\n2. **ShiftRows**: Rows of the state (the 16-byte block treated as a 4x4 matrix) are shifted.\n3. **MixColumns**: A mixing operation combining the bytes in each column of the state (except in the final round).\n4. **AddRoundKey**: The round key, derived from the encryption key, is XOR-ed with the block.\n\n### **Ciphertext:**\n\nAfter all the rounds are complete, a **16-byte (128-bit) block of ciphertext** is produced.  \nIf the plaintext exceeds 16 bytes, AES processes the data in **multiple 16-byte blocks**, generating 16 bytes of ciphertext for each block.\n\n---\n\n## **ECB (Electronic Codebook) Mode:**\n\nECB is one of the simplest block cipher modes of operation. In ECB mode:\n\n- The plaintext is divided into **16-byte blocks**.\n- Each block is **independently encrypted** using the same key.\n- If the plaintext is not a multiple of 16 bytes, padding is applied to the final block.\n- The resulting ciphertext blocks are concatenated to form the final encrypted message.\n\n### **How AES-ECB Works:**\n\n1. **Plaintext** is divided into 16-byte blocks.  \n2. **Each block** is independently encrypted using AES and the same key.\n3. The **resulting ciphertext** blocks are concatenated.\n\n   ![Wikipedia ECB Penguin Image](https://github.com/5olitude/AES_ECB-DECODER/blob/7a2a45ad849d19343d4fe402bba6ac78275a88f3/Screens.png)\n---\n\n## **Real-World Example: ECB Penguin Attack**\n\nThe **ECB Penguin** is a famous example illustrating the weakness of AES-ECB mode. When an image (like the famous penguin image) is encrypted using ECB, **repeating patterns** in the plaintext are easily visible in the ciphertext. This happens because identical plaintext blocks are encrypted into identical ciphertext blocks, making the encrypted image resemble the original.  \nLearn more about the **ECB Penguin** from this [GitHub link](https://github.com/robertdavidgraham/ecb-penguin).\n\nYou can also refer to the following Wikipedia illustration:\n\n\n\n### **Other Real-World Attacks**:\n\nOne example is the **Adobe Password Database Leak**, where identical passwords produced identical ciphertexts. This allowed attackers to locate frequently reused passwords, leading to significant data breaches.\n\nHere is a comic from **XKCD** that humorously illustrates this vulnerability:\n\n![XKCD Encryptic Comic](https://imgs.xkcd.com/comics/encryptic_2x.png)\n\nFor a detailed explanation, refer to this [StackExchange discussion](https://crypto.stackexchange.com/questions/14487/can-someone-explain-the-ecb-penguin).\n\n\n### CODE LOGIC IN GOLANG \n\n```go\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"image\"\n\t\"image/color\"\n\t\"image/png\"\n\t\"log\"\n\t\"math\"\n\t\"os\"\n\t\"sort\"\n)\n\nfunc main() {\n\tcolors_needed := 254\n\tflip := true\n\tpix_width := 16\n        \n\timage_location := \"aes.bmp\"  //please specify the path of the image you wanna decrypt\n\tblock_size := 16    //the block size in ecb mode as we learned 16 bytes\n\n\n        //Redaing the image as bytes \n\tbytes, err := os.ReadFile(image_location)\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to read input file: %v\", err)\n\t}\n\n\n       //Adjusts the byte slice to remove any remaining bytes that do not form a complete block of size\n       //block_size (i.e., 16 bytes). This ensures that only full blocks are processed.\n\n\tbytes = bytes[:len(bytes)-(len(bytes)%block_size)] \n\n\n      // Creates a slice of byte slices (blocks) to hold the individual 16-byte blocks. It loops through the bytes slice, slicing it into blocks and appending each          block to blocks.\n\n\tblocks := make([][]byte, 0)\n\tfor i := 0; i \u003c len(bytes); i += block_size {\n\t\tblock := bytes[i : i+block_size]\n\t\tblocks = append(blocks, block)\n\t}\n\n        // initializes a map block_counts to keep track of how many times each block appears. It iterates over the blocks, converting each block to a string key and incrementing its count in the map.\n\n\tblock_counts := make(map[string]int)\n\tfor _, block := range blocks {\n\t\tblockKey := string(block)\n\t\tblock_counts[blockKey]++\n\t}\n\n       // Defines a struct BlockFrequencifier to hold a block's key and its frequency count.\n\ttype BlockFrequencifier struct {\n\t\tBlockKey string\n\t\tCount    int\n\t}\n\n       // Initializes a slice block_frequencies to hold the frequency of each block. It iterates over block_counts, creating an instance of BlockFrequencifier for          // each block and appending it to block_frequencies\n\n\tblock_frequencies := make([]BlockFrequencifier, 0, len(block_counts))\n\tfor k, v := range block_counts {\n\t\tblock_frequencies = append(block_frequencies, BlockFrequencifier{BlockKey: k, Count: v})\n\t}\n\n\n        //Sorts the block_frequencies slice in descending order based on the Count field. This helps prioritize the most frequent blocks.\n\tsort.Slice(block_frequencies, func(i, j int) bool {\n\t\treturn block_frequencies[i].Count \u003e block_frequencies[j].Count\n\t})\n\n\n       //Initializes a colorMap to associate block strings with colors. Also, it creates a palette slice to hold the colors, starting with white as the first color.\n\tcolorMap := make(map[string]color.Color)\n\tpalette := make([]color.Color, 0, colors_needed)\n\tpalette = append(palette, color.White) // First color is white\n\n       //This loop generates a color palette with the specified number of colors. Each color is generated with varying values for red, green, and blue components,         //ensuring diversity. Finally, black is added as the last color.\n\tfor i := 1; i \u003c colors_needed-1; i++ {\n\n\t\tclr := color.RGBA{\n\t\t\tR: uint8((i * 50) % 255),\n\t\t\tG: uint8((i * 80) % 255),\n\t\t\tB: uint8((i * 110) % 255),\n\t\t\tA: 255,\n\t\t}\n\t\tpalette = append(palette, clr)\n\t}\n\tpalette = append(palette, color.Black) // Last color is black\n\n\t// Map blocks to colors\n\tfor i, bf := range block_frequencies {\n\t\tvar clr color.Color\n\t\tif i \u003c colors_needed-1 {\n\t\t\tclr = palette[i]\n\t\t} else {\n\t\t\tclr = palette[len(palette)-1] // Assign black to less frequent blocks\n\t\t}\n\t\tcolorMap[bf.BlockKey] = clr\n\t}\n\n\t// Map data blocks to color indices\n\tpixelData := make([]color.Color, 0, len(blocks)*pix_width)\n\tfor _, block := range blocks {\n\t\tblockKey := string(block)\n\t\tclr, exists := colorMap[blockKey]\n\t\tif !exists {\n\t\t\tclr = color.Black\n\t\t}\n\t\tfor i := 0; i \u003c block_size/pix_width; i++ {\n\t\t\tpixelData = append(pixelData, clr)\n\t\t}\n\t}\n\n\t// Calculate image dimensions\n\ttotalPixels := len(pixelData)\n\twidth := int(math.Sqrt(float64(totalPixels)))\n\theight := totalPixels / width\n\n\tif totalPixels%width != 0 {\n\t\theight++\n\t}\n\n\timg := image.NewRGBA(image.Rect(0, 0, width, height))\n\n\tfor idx, clr := range pixelData {\n\t\tx := idx % width\n\t\ty := idx / width\n\t\tif flip {\n\t\t\ty = height - y - 1 // Correctly calculate the flipped y-coordinate\n\t\t}\n\t\tif y \u003e= height {\n\t\t\tbreak\n\t\t}\n\t\timg.Set(x, y, clr)\n\t}\n\n\tdest_file := fmt.Sprintf(\"%s_aes.png\", image_location)\n\toutFile, err := os.Create(dest_file)\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to genearte image: %v\", err)\n\t}\n\tdefer outFile.Close()\n\n\tbuf := bufio.NewWriter(outFile)\n\tif err := png.Encode(buf, img); err != nil {\n\t\tlog.Fatalf(\"Encoder failed: %v\", err)\n\t}\n\tif err := buf.Flush(); err != nil {\n\t\tlog.Fatalf(\"File Witer Failed: %v\", err)\n\t}\n\n\tfmt.Printf(\"Image saved to %s\\n\", dest_file)\n}\n\n\n\n\n\n\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F5olitude%2Faes_ecb-decoder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F5olitude%2Faes_ecb-decoder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F5olitude%2Faes_ecb-decoder/lists"}