隱寫術是一種將秘密訊息隱藏於公開資訊中的技術,本文將以 Python 為例,示範如何將訊息嵌入圖片中。首先,訊息會被轉換為位元序列,然後嵌入到圖片的畫素中,修改畫素的最低有效位以隱藏訊息。這個過程需要仔細處理位元操作,確保訊息可以被正確地嵌入和提取。同時,為了驗證訊息的完整性,我們會使用雜湊演算法產生訊息摘要,並使用金鑰加密摘要,以防止竄改。最後,為了更進一步提升安全性,可以將嵌入訊息的圖片封裝成 ZIP 檔案,並將加密後的訊息摘要儲存在 ZIP 檔案的註解中。

資訊隱藏技術:使用隱寫術編碼秘密訊息

隱寫術是一種將秘密訊息隱藏在公開資訊中的技術。我們將探討如何使用Python將秘密訊息編碼成圖片。

字串轉換為位元組和位元

首先,我們需要將字串轉換為位元組和位元。我們可以使用UTF-8編碼將字串轉換為位元組。

message = "http://www.kearsarge.navy.mil"
message_bytes = message.encode("UTF-8")
print(message_bytes)

輸出結果為:

b'http://www.kearsarge.navy.mil'

內容解密:

這段程式碼將字串message使用UTF-8編碼轉換為位元組。UTF-8編碼是一種廣泛使用的編碼方式,可以將Unicode字元轉換為位元組。在這個例子中,由於字串只包含ASCII字元,因此UTF-8編碼後的結果與原始字串相似。

位元組轉換為位元

接下來,我們需要將位元組轉換為位元。我們可以定義兩個函式:to_bitsto_byte

def to_bits(v):
    b = []
    for i in range(8):
        b.append(v & 1)
        v >>= 1
    return tuple(reversed(b))

def to_byte(b):
    v = 0
    for bit in b:
        v = (v << 1) | bit
    return v

內容解密:

to_bits函式將一個位元組轉換為8個位元。它使用位運算來提取每個位元,並將結果儲存在一個列表中。to_byte函式則相反,將8個位元轉換回一個位元組。這兩個函式可以用來測試和驗證位元組和位元之間的轉換。

測試位元組和位元之間的轉換

我們可以使用一個迴圈來測試to_bitsto_byte函式。

for test in range(256):
    b = to_bits(test)
    v = to_byte(b)
    assert v == test

內容解密:

這段程式碼測試了to_bitsto_byte函式的正確性。它將0到255之間的所有整數轉換為位元,然後再轉換回整數,並驗證結果是否正確。

將訊息轉換為位元

現在,我們可以將訊息轉換為位元。

message_bytes = message.encode("UTF-8")
bits = list(to_bits(c) for c in message_bytes)
print(bits)

輸出結果為:

[(0, 1, 1, 0, 1, 0, 0, 0), (0, 1, 1, 1, 0, 1, 0, 0), (0, 1, 1, 1, 0, 1, 0, 0), (0, 1, 1, 1, 0, 0, 0, 0), (0, 0, 1, 1, 1, 0, 1, 0), (0, 0, 1, 0, 1, 1, 1, 1), (0, 0, 1, 0, 1, 1, 1, 1), (0, 1, 1, 1, 0, 1, 1, 1), (0, 1, 1, 0, 1, 1, 1, 0), (0, 1, 1, 0, 1, 1, 1, 0), (0, 1, 1, 0, 1, 1, 1, 0), (0, 0, 1, 0, 1, 1, 1, 0), (0, 1, 1, 0, 1, 0, 1, 1), (0, 1, 1, 0, 0, 1, 0, 1), (0, 1, 1, 0, 0, 0, 0, 1), (0, 1, 1, 1, 0, 0, 1, 0), (0, 1, 1, 1, 0 , ...]

圖表說明:訊息轉換過程

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 圖表說明:訊息轉換過程

rectangle "UTF-8編碼" as node1
rectangle "to_bits函式" as node2
rectangle "隱寫術" as node3

node1 --> node2
node2 --> node3

@enduml

此圖示展示了將原始訊息轉換為位元的過程。首先,使用UTF-8編碼將原始訊息轉換為位元組。然後,使用to_bits函式將位元組轉換為位元。最終,這些位元被用於隱寫術,將訊息隱藏在圖片中。

資訊隱藏技術:訊息編碼實作

資訊隱藏(Steganography)是一種將秘密訊息隱藏在公開媒體中的技術,常見的做法是將訊息嵌入圖片中。以下將詳細介紹如何實作訊息的編碼與解碼。

組合位元序列

要將訊息隱藏在圖片中,首先需要將訊息轉換為位元序列。我們可以透過以下步驟達成:

  1. 將訊息編碼為位元組(bytes)。
  2. 將每個位元組轉換為 8 位元的二進位表示。

位元序列生成器

為了有效地處理大量位後設資料,我們可以使用生成器(generator)函式來逐步產生位元序列,而非一次性將所有位元載入記憶體。

def bit_sequence(list_of_tuples):
    for t8 in list_of_tuples:
        for b in t8:
            yield b

這個生成器函式接受一個由 8 位元 Tuple 組成的列表,並逐一產生每個位元。

將位元序列轉換為位元組

為了將位元序列重新轉換為原始的位元組資料,我們需要將 8 個位元組成一個位元組。

def byte_sequence(bits):
    byte = []
    for n, b in enumerate(bits):
        if n % 8 == 0 and n != 0:
            yield to_byte(byte)
            byte = []
        byte.append(b)
    yield to_byte(byte)

內容解密:

  1. bit_sequence 函式負責將 8 位元 Tuple 列表轉換為單一位元的序列。
  2. byte_sequence 函式則是將單一位元序列重新組合為位元組。
  3. 使用 enumerate 來追蹤位元的索引,以便在每 8 個位元時產生一個位元組。

編碼訊息

在將訊息隱藏到圖片之前,我們需要先對訊息進行編碼,並加入長度資訊,以便解碼時知道何時停止。

編碼流程:

  1. 將訊息轉換為 UTF-8 編碼的位元組。
  2. 計算訊息的長度,並將其表示為 2 個位元組(高位元組和低位元組)。
  3. 將長度資訊和訊息內容合併成一個位元序列。
message_bytes = message.encode("UTF-8")
bits_list = list(to_bits(c) for c in message_bytes)
len_h, len_l = divmod(len(message_bytes), 256)
size_list = [to_bits(len_h), to_bits(len_l)]
bit_sequence(size_list + bits_list)

內容解密:

  1. message.encode("UTF-8") 將訊息轉換為 UTF-8 編碼的位元組。
  2. 使用 divmod 計算訊息長度的高低位元組。
  3. 將長度資訊和訊息內容的位元表示合併,以便嵌入圖片。

隱寫術中的秘密訊息編碼技術深度解析

隱寫術是一種將秘密訊息隱藏在公開媒體中的技術,常見的做法是將訊息嵌入圖片中。本文將探討如何使用Python實作圖片隱寫術,包括編碼和解碼的過程。

編碼過程:將秘密訊息嵌入圖片

首先,我們需要將秘密訊息轉換成二進位序列,然後將其嵌入圖片的畫素中。以下是具體步驟:

  1. 準備圖片:選擇一張圖片作為載體,並將其開啟。
  2. 轉換訊息為二進位序列:將秘密訊息轉換成二進位序列。
  3. 嵌入訊息:使用putpixel()getpixel()方法更新圖片的畫素,將二進位序列嵌入紅色通道的最低位。
w, h = ship.size
for p, m in enumerate(bit_sequence(size_list + bits_list)):
    y, x = divmod(p, w)
    r, g, b = ship.getpixel((x, y))
    r_new = (r & 0xfe) | m
    print((r, g, b), m, (r_new, g, b))
    ship.putpixel((x, y), (r_new, g, b))

內容解密:

  • w, h = ship.size:取得圖片的寬度和高度。
  • divmod(p, w):將畫素位置p轉換成座標(x, y)
  • r & 0xfe:將紅色通道的最低位設為0。
  • (r & 0xfe) | m:將二進位序列m嵌入紅色通道的最低位。

解碼過程:提取隱藏的秘密訊息

解碼過程需要提取嵌入在圖片中的二進位序列,並將其轉換回原始的秘密訊息。

  1. 提取二進位序列:使用get_bits()函式從圖片中提取紅色通道的最低位。
  2. 轉換二進位序列為原始訊息:使用byte_sequence()函式將二進位序列轉換成原始的秘密訊息。
def get_bits(image, offset=0, size=16):
    w, h = image.size
    for p in range(offset, offset + size):
        y, x = divmod(p, w)
        r, g, b = image.getpixel((x, y))
        yield r & 0x01

size_H, size_L = byte_sequence(get_bits(ship, 0, 16))
size = size_H * 256 + size_L
message = byte_sequence(get_bits(ship, 16, size * 8))

內容解密:

  • get_bits()函式:從圖片中提取紅色通道的最低位,生成二進位序列。
  • byte_sequence()函式:將二進位序列轉換成原始的秘密訊息。
  • size_H * 256 + size_L:計算原始訊息的大小。

重建原始訊息

最後,使用Python的bytes.decode()方法將提取的位元組序列解碼成原始的字串。

print(bytes(message).decode("UTF-8"))

內容解密:

  • bytes(message):將位元組序列轉換成bytes物件。
  • .decode("UTF-8"):使用UTF-8編碼將bytes物件解碼成字串。

使用隱寫術確保訊息完整性

隱寫術可用於確保訊息在傳輸過程中未被竄改。如果我們無法正確解碼嵌入的數位浮水印,就表示圖片已被竄改。這是一種檢測竄改的方法。更強健的方法是使用雜湊值(hash totals)。有多種雜湊演算法可用於產生一系列位元組的摘要或簽章。我們將訊息和雜湊碼分開傳送。如果收到的訊息與雜湊碼不匹配,就表示傳輸過程中出了問題。

使用雜湊值驗證檔案

Python 的 hashlib 模組提供了多種雜湊演算法。軟體下載通常會提供軟體套件的 MD5 雜湊值。我們可以使用 hashlib 計算檔案的 MD5 摘要,如下所示:

import hashlib
md5 = hashlib.new("md5")
with open("LHD_warship.jpg", "rb") as some_file:
    md5.update(some_file.read())
print(md5.hexdigest())

內容解密:

  1. 建立 MD5 摘要物件:使用 hashlib.new("md5") 建立一個 MD5 摘要物件,用於計算檔案的雜湊值。
  2. 開啟檔案:以二進位模式 ("rb")開啟檔案 LHD_warship.jpg,確保讀取的是原始位元組資料。
  3. 更新摘要:將檔案內容傳遞給 md5.update() 方法,計算檔案的 MD5 雜湊值。對於大檔案,可以分塊讀取以避免一次性載入整個檔案到記憶體。
  4. 輸出十六進位雜湊值:使用 md5.hexdigest() 輸出 MD5 雜湊值的十六進位字串表示。

輸出範例:

0032e5b0d9dd6e3a878a611b49807d24

這個安全的雜湊值允許我們確認檔案在傳輸過程中未被竄改。

使用金鑰增強訊息摘要安全性

我們可以透過新增金鑰到訊息摘要來提供額外的安全性。這不會加密訊息本身,而是加密摘要以確保摘要在傳輸過程中未被竄改。

Python 的 hmac 模組處理了這項工作,如下所示:

import hmac
with open("LHD_warship.jpg", "rb") as some_file:
    keyed = hmac.new(b"Agent Garbo", some_file.read())
print(keyed.hexdigest())

內容解密:

  1. 建立 HMAC 摘要物件:使用 hmac.new(b"Agent Garbo", ...) 建立一個 HMAC 摘要物件,其中 b"Agent Garbo" 是金鑰。
  2. 傳遞檔案內容:將檔案內容傳遞給 HMAC 摘要物件,計算帶有金鑰的雜湊值。
  3. 輸出十六進位雜湊值:使用 keyed.hexdigest() 輸出 HMAC 雜湊值的十六進位字串表示。

輸出範例:

42212d077cc5232f3f2da007d35a726c

HQ 知道我們的金鑰,因此可以確認訊息是否來自我們。同樣,當 HQ 向我們傳送訊息時,我們可以使用相同的金鑰驗證訊息的真實性。

加密訊息的挑戰

雖然加密似乎可以防止竄改,但它需要謹慎管理加密金鑰。加密並非萬能藥。使用良好的加密演算法但失去對金鑰的控制,會使加密變得無效。擁有未授權金鑰的人可以重寫檔案而無人知曉。

結合隱寫術與 ZIP 壓縮

我們可以將隱寫術與建立 ZIP 檔案結合,將訊息嵌入圖片中,並將其封裝成 ZIP 檔案。由於 ZIP 檔案可以包含註解字串,我們可以在 ZIP 檔案的註解中加入 HMAC 簽章。

定義封裝函式

def package(text, image_source, key_hmac, filename):
    image = Image.open(image_source)
    steg_embed(image, text)
    image.save("/tmp/package.tiff", format="TIFF")
    with open("/tmp/package.tiff", "rb") as saved:
        digest = hmac.new(key_hmac.encode("ASCII"), saved.read())
    with ZipFile(filename, "w") as archive:
        archive.write("/tmp/package.tiff", "image.tiff")
        archive.comment = digest.hexdigest().encode("ASCII")
    os.remove("/tmp/package.tiff")

內容解密:

  1. 開啟圖片:使用 Image.open(image_source) 開啟來源圖片。
  2. 嵌入訊息:呼叫 steg_embed(image, text) 將秘密訊息嵌入圖片中。
  3. 儲存圖片:將更新後的圖片儲存到臨時檔案 /tmp/package.tiff
  4. 計算 HMAC 摘要:讀取臨時檔案並計算其 HMAC 摘要,使用提供的金鑰 key_hmac
  5. 建立 ZIP 壓縮檔:建立一個新的 ZIP 檔案,將處理後的圖片寫入其中,並將 HMAC 摘要作為 ZIP 檔案的註解。
  6. 清理臨時檔案:刪除臨時檔案 /tmp/package.tiff 以避免留下潛在的證據。

這個過程結合了隱寫術和加密技術,提高了訊息傳輸的安全性。接下來,我們需要實作 steg_embed() 函式來完成隱寫編碼的工作。

地理定位資訊與隱寫術的整合應用

在前一章中,我們探討瞭如何利用隱寫術在影像檔案中隱藏訊息。本章將進一步擴充套件相關技術,結合地理定位資訊與網路服務,實作更複雜的資料蒐集與分析。

解碼隱藏訊息的函式實作

要完整實作隱寫術的應用,我們需要實作 steg_extract() 函式,用於從影像中提取隱藏的訊息。該函式的實作細節將在後續章節中詳細說明。

解封裝函式 unpackage()

首先,我們需要實作一個用於解封裝 ZIP 檔案的函式 unpackage(),其定義如下:

def unpackage(filename, key_hmac):
    try:
        os.remove("/tmp/image.tiff")
    except FileNotFoundError:
        pass
    with ZipFile(filename, "r") as archive:
        with archive.open("image.tiff", "r") as member:
            keyed = hmac.new(key_hmac.encode("ASCII"), member.read())
            assert archive.comment == keyed.hexdigest().encode("ASCII"), "Invalid HMAC"
        archive.extract("image.tiff", "/tmp")
        image = Image.open("/tmp/image.tiff")
        text = steg_extract(image)
        os.remove("/tmp/image.tiff")
        return text, image

#### 內容解密:

  1. 移除暫存檔案:首先嘗試刪除暫存檔案 /tmp/image.tiff,若檔案不存在則捕捉 FileNotFoundError 例外並忽略。
  2. 開啟 ZIP 檔案:使用 ZipFile 開啟指定的 ZIP 檔案,並讀取其中的 image.tiff 成員。
  3. 驗證 HMAC:計算 image.tiff 的 HMAC 值,並與 ZIP 檔案的註解進行比對。若驗證失敗,則丟出例外。
  4. 提取影像檔案:將 image.tiff 提取到 /tmp 目錄下,並開啟該影像檔案。
  5. 提取隱藏訊息:使用 steg_extract() 函式從影像中提取隱藏的訊息。
  6. 清理暫存檔案:刪除提取出的影像檔案 /tmp/image.tiff
  7. 傳回結果:傳回提取出的訊息和影像物件。

地理定位資訊的基礎知識

在進行地理定位資訊處理之前,我們需要了解一些基本的術語和概念。

全球定位系統(GPS)

GPS 是一種根據衛星的定位系統,能夠精確地確定接收器的位置和時間。每顆 GPS 衛星都會傳送包含其位置和精確時間戳的資料流。接收器透過接收多個衛星的資料,可以計算出自己的位置。

緯度和經度

  • 緯度:是相對於赤道和極點測量的角度,需提供方向(N 或 S)。例如,36°50′40.12′′N 表示北緯。
  • 經度:是相對於本初子午線(格林威治子午線)測量的角度,向東為正,向西為負。例如,76°17′35.21′′W 可表示為 -76.293114。

球面幾何

由於地球是球體,經緯度的計算需要使用球面幾何而非簡單的平面幾何。緯度線是與赤道平行的,而經度線則在南北極相交。