在现代科技中,GPS设备被广泛应用于记录和交换地理位置信息。GPX文件格式是GPS设备用来存储这些信息的标准格式之一。本文将探讨一种新颖的方法,即在GPX文件中隐藏额外的信息。这种方法类似于椭圆曲线密码学中的点编码,通过改变GPS轨迹中的特定经度值来实现信息的编码。
GPX文件是一种基于XML的格式,用于存储地理数据。它通常包含轨迹点(轨迹或路线)和命名点(航点)。文件结构简单明了,易于理解和操作。
<gpx version="1.0"/>
<trk>
<name>轨迹</name>
<trkseg>
<trkpt lat="52.311389" lon="9.787149">
[可选数据]
</trkpt>
<trkpt lat="52.311276" lon="9.787381">
[可选数据]
</trkpt>
</trkseg>
</trk>
<wpt lat="52.310218" lon="9.791205">
<name><![CDATA[地点]]></name>
[可选数据]
</wpt>
在GPX文件中,纬度和经度的值比常见的接收器更为精确,小数点后第六位的变化意味着10厘米的变化。因此,隐藏额外信息的一个想法是改变最不显著的小数位,这可以看作是一种地理最低有效位(Geo LSB),与像素颜色的最低有效位类似。
有一种众所周知的方法可以将任何数据编码为给定曲线上的点。将x轴分成相等的列,对这些列进行编号,然后为每个要编码的值选择相应列中的一个点。对于纯文本消息,甚至可以像下面这样划分地图:
例如,在椭圆曲线密码学中,会进行一些奇怪的计算来处理选定的点。但是,如果熟悉文章,会知道会避免复杂的数学计算。也会从给定的池中选择点,但会保持它们的原样,使它们看起来无害。
通常,GPX文件是在行走时记录的,或者在地图上绘制的。人们还会将特殊地点标记为航点。当然,每个航点也是(记录的,不是绘制的)轨迹的一部分:轨迹的作者必须去那里记录航点。这是昨天记录的一些GPS数据。有很多路径和两个航点。
不知道那个区域,对吧?可以把航点放在任何地方。甚至可以发布一个航点文件,加载到GPS设备上——只要周围有漂亮的东西(以防有人真的走到那里),这看起来并不奇怪。这个想法是标记编码消息的航点。根据文本或二进制流,从轨迹中取出点,然后写入空白的航点文件或轨迹的GPX文件。人们可以自由地在地图上查看这些文件或将它们导入到他们的GPS设备上。但是,只有那些解码某些点的经度的人才能看见隐藏的消息。
从轨迹中得到的原始坐标是浮点值,小数点后有六位。在能够编码0到255之间的字节值之前,需要以某种方式压缩它们。决定将整个轨迹进行缩放,使得最小的经度为0,最大的为255。这段代码读取XML节点中的点,并获取最小和最大的坐标:
// 查找所有轨迹点节点
XmlNodeList trackPoints = gpxDocument.GetElementsByTagName("trkpt");
// 将节点转换为点
ScalablePoint[] track = GeoNodeToPoints(trackPoints);
// 将轨迹移动到左上角
ScaleTrack(track);
以下是将轨迹压缩到255x255矩阵中的代码。也对纬度进行了缩放,因为轨迹将在图片框中显示。
private void ScaleTrack(ScalablePoint[] track)
{
int scaledMaxLon = maxLon - minLon;
int scaledMaxLat = maxLat - minLat;
for (int n = 0; n < track.Length; n++)
{
// 将轨迹移动到左上角
track[n].X -= minLon;
track[n].Y -= minLat;
// 将轨迹缩放到宽度 = 高度 = 256 = 每列一个可能的消息字节
track[n].X = (int)Math.Round((track[n].X / (float)scaledMaxLon) * 255);
track[n].Y = (int)Math.Round((track[n].Y / (float)scaledMaxLat) * 255);
}
}
当轨迹被缩放到0到255之间的经度时,就可以开始编码了!对于秘密消息的每个字节,取一个具有相应缩放经度的点。然后,将这个点写入航点GPX文件,并上传到一个知名的网站。
所以,从一个户外狂热者的网站下载了一个GPX文件。是知道在哪里寻找的人。不是用行程规划器打开它,而是用解码应用程序打开它。这段代码从文件中获取航点,并使用之前用于缩放密钥轨迹的相同参数进行缩放。然后,可以从x值中读取消息。
private void btnDecode_Click(object sender, EventArgs e)
{
XmlDocument gpxDocument = new XmlDocument();
gpxDocument.Load(fsWaypoints.FileName);
XmlNodeList wayPointNodes = gpxDocument.GetElementsByTagName("wpt");
ScalablePoint[] wayPoints = GeoNodeToPoints(wayPointNodes);
ScaleTrack(wayPoints);
char[] messageChars = new char[wayPoints.Length];
for (int n = 0; n < messageChars.Length; n++)
{
messageChars[n] = (char)wayPoints[n].X;
}
txtDecodedMessage.Text = new string(messageChars);
}